Annotation of mandoc/dbm_map.c, Revision 1.2
1.2 ! schwarze 1: /* $Id: dbm_map.c,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
1.1 schwarze 2: /*
3: * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: *
17: * Low-level routines for the map-based version
18: * of the mandoc database, for read-only access.
19: * The interface is defined in "dbm_map.h".
20: */
1.2 ! schwarze 21: #include "config.h"
! 22:
1.1 schwarze 23: #include <sys/mman.h>
24: #include <sys/stat.h>
25: #include <sys/types.h>
26:
27: #include <endian.h>
1.2 ! schwarze 28: #if HAVE_ERR
1.1 schwarze 29: #include <err.h>
1.2 ! schwarze 30: #endif
1.1 schwarze 31: #include <errno.h>
32: #include <fcntl.h>
33: #include <regex.h>
34: #include <stdint.h>
35: #include <stdlib.h>
36: #include <string.h>
37: #include <unistd.h>
38:
39: #include "mansearch.h"
40: #include "dbm_map.h"
41: #include "dbm.h"
42:
43: static struct stat st;
44: static char *dbm_base;
45: static int ifd;
46: static int32_t max_offset;
47:
48: /*
49: * Open a disk-based database for read-only access.
50: * Validate the file format as far as it is not mandoc-specific.
51: * Return 0 on success. Return -1 and set errno on failure.
52: */
53: int
54: dbm_map(const char *fname)
55: {
56: int save_errno;
57: const int32_t *magic;
58:
59: if ((ifd = open(fname, O_RDONLY)) == -1)
60: return -1;
61: if (fstat(ifd, &st) == -1)
62: goto fail;
63: if (st.st_size < 5) {
64: warnx("dbm_map(%s): File too short", fname);
65: errno = EFTYPE;
66: goto fail;
67: }
68: if (st.st_size > INT32_MAX) {
69: errno = EFBIG;
70: goto fail;
71: }
72: if ((dbm_base = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED,
73: ifd, 0)) == MAP_FAILED)
74: goto fail;
75: magic = dbm_getint(0);
76: if (be32toh(*magic) != MANDOCDB_MAGIC) {
77: warnx("dbm_map(%s): Bad initial magic %x (expected %x)",
78: fname, be32toh(*magic), MANDOCDB_MAGIC);
79: errno = EFTYPE;
80: goto fail;
81: }
82: magic = dbm_getint(1);
83: if (be32toh(*magic) != MANDOCDB_VERSION) {
84: warnx("dbm_map(%s): Bad version number %d (expected %d)",
85: fname, be32toh(*magic), MANDOCDB_VERSION);
86: errno = EFTYPE;
87: goto fail;
88: }
89: max_offset = be32toh(*dbm_getint(3)) + sizeof(int32_t);
90: if (st.st_size != max_offset) {
91: warnx("dbm_map(%s): Inconsistent file size %llu (expected %d)",
92: fname, st.st_size, max_offset);
93: errno = EFTYPE;
94: goto fail;
95: }
96: if ((magic = dbm_get(*dbm_getint(3))) == NULL) {
97: errno = EFTYPE;
98: goto fail;
99: }
100: if (be32toh(*magic) != MANDOCDB_MAGIC) {
101: warnx("dbm_map(%s): Bad final magic %x (expected %x)",
102: fname, be32toh(*magic), MANDOCDB_MAGIC);
103: errno = EFTYPE;
104: goto fail;
105: }
106: return 0;
107:
108: fail:
109: save_errno = errno;
110: close(ifd);
111: errno = save_errno;
112: return -1;
113: }
114:
115: void
116: dbm_unmap(void)
117: {
118: if (munmap(dbm_base, st.st_size) == -1)
119: warn("dbm_unmap: munmap");
120: if (close(ifd) == -1)
121: warn("dbm_unmap: close");
122: dbm_base = (char *)-1;
123: }
124:
125: /*
126: * Take a raw integer as it was read from the database.
127: * Interpret it as an offset into the database file
128: * and return a pointer to that place in the file.
129: */
130: void *
131: dbm_get(int32_t offset)
132: {
133: offset = be32toh(offset);
134: if (offset < 0 || offset >= max_offset) {
135: warnx("dbm_get: Database corrupt: offset %d > %d",
136: offset, max_offset);
137: return NULL;
138: }
139: return dbm_base + offset;
140: }
141:
142: /*
143: * Assume the database starts with some integers.
144: * Assume they are numbered starting from 0, increasing.
145: * Get a pointer to one with the number "offset".
146: */
147: int32_t *
148: dbm_getint(int32_t offset)
149: {
150: return (int32_t *)dbm_base + offset;
151: }
152:
153: /*
154: * The reverse of dbm_get().
155: * Take pointer into the database file
156: * and convert it to the raw integer
157: * that would be used to refer to that place in the file.
158: */
159: int32_t
160: dbm_addr(const void *p)
161: {
162: return htobe32((char *)p - dbm_base);
163: }
164:
165: int
166: dbm_match(const struct dbm_match *match, const char *str)
167: {
168: switch (match->type) {
169: case DBM_EXACT:
170: return strcmp(str, match->str) == 0;
171: case DBM_SUB:
172: return strcasestr(str, match->str) != NULL;
173: case DBM_REGEX:
174: return regexec(match->re, str, 0, NULL, 0) == 0;
175: default:
176: abort();
177: }
178: }
CVSweb