Annotation of mandoc/dbm_map.c, Revision 1.1
1.1 ! schwarze 1: /* $Id$ */
! 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: */
! 21: #include <sys/mman.h>
! 22: #include <sys/stat.h>
! 23: #include <sys/types.h>
! 24:
! 25: #include <endian.h>
! 26: #include <err.h>
! 27: #include <errno.h>
! 28: #include <fcntl.h>
! 29: #include <regex.h>
! 30: #include <stdint.h>
! 31: #include <stdlib.h>
! 32: #include <string.h>
! 33: #include <unistd.h>
! 34:
! 35: #include "mansearch.h"
! 36: #include "dbm_map.h"
! 37: #include "dbm.h"
! 38:
! 39: static struct stat st;
! 40: static char *dbm_base;
! 41: static int ifd;
! 42: static int32_t max_offset;
! 43:
! 44: /*
! 45: * Open a disk-based database for read-only access.
! 46: * Validate the file format as far as it is not mandoc-specific.
! 47: * Return 0 on success. Return -1 and set errno on failure.
! 48: */
! 49: int
! 50: dbm_map(const char *fname)
! 51: {
! 52: int save_errno;
! 53: const int32_t *magic;
! 54:
! 55: if ((ifd = open(fname, O_RDONLY)) == -1)
! 56: return -1;
! 57: if (fstat(ifd, &st) == -1)
! 58: goto fail;
! 59: if (st.st_size < 5) {
! 60: warnx("dbm_map(%s): File too short", fname);
! 61: errno = EFTYPE;
! 62: goto fail;
! 63: }
! 64: if (st.st_size > INT32_MAX) {
! 65: errno = EFBIG;
! 66: goto fail;
! 67: }
! 68: if ((dbm_base = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED,
! 69: ifd, 0)) == MAP_FAILED)
! 70: goto fail;
! 71: magic = dbm_getint(0);
! 72: if (be32toh(*magic) != MANDOCDB_MAGIC) {
! 73: warnx("dbm_map(%s): Bad initial magic %x (expected %x)",
! 74: fname, be32toh(*magic), MANDOCDB_MAGIC);
! 75: errno = EFTYPE;
! 76: goto fail;
! 77: }
! 78: magic = dbm_getint(1);
! 79: if (be32toh(*magic) != MANDOCDB_VERSION) {
! 80: warnx("dbm_map(%s): Bad version number %d (expected %d)",
! 81: fname, be32toh(*magic), MANDOCDB_VERSION);
! 82: errno = EFTYPE;
! 83: goto fail;
! 84: }
! 85: max_offset = be32toh(*dbm_getint(3)) + sizeof(int32_t);
! 86: if (st.st_size != max_offset) {
! 87: warnx("dbm_map(%s): Inconsistent file size %llu (expected %d)",
! 88: fname, st.st_size, max_offset);
! 89: errno = EFTYPE;
! 90: goto fail;
! 91: }
! 92: if ((magic = dbm_get(*dbm_getint(3))) == NULL) {
! 93: errno = EFTYPE;
! 94: goto fail;
! 95: }
! 96: if (be32toh(*magic) != MANDOCDB_MAGIC) {
! 97: warnx("dbm_map(%s): Bad final magic %x (expected %x)",
! 98: fname, be32toh(*magic), MANDOCDB_MAGIC);
! 99: errno = EFTYPE;
! 100: goto fail;
! 101: }
! 102: return 0;
! 103:
! 104: fail:
! 105: save_errno = errno;
! 106: close(ifd);
! 107: errno = save_errno;
! 108: return -1;
! 109: }
! 110:
! 111: void
! 112: dbm_unmap(void)
! 113: {
! 114: if (munmap(dbm_base, st.st_size) == -1)
! 115: warn("dbm_unmap: munmap");
! 116: if (close(ifd) == -1)
! 117: warn("dbm_unmap: close");
! 118: dbm_base = (char *)-1;
! 119: }
! 120:
! 121: /*
! 122: * Take a raw integer as it was read from the database.
! 123: * Interpret it as an offset into the database file
! 124: * and return a pointer to that place in the file.
! 125: */
! 126: void *
! 127: dbm_get(int32_t offset)
! 128: {
! 129: offset = be32toh(offset);
! 130: if (offset < 0 || offset >= max_offset) {
! 131: warnx("dbm_get: Database corrupt: offset %d > %d",
! 132: offset, max_offset);
! 133: return NULL;
! 134: }
! 135: return dbm_base + offset;
! 136: }
! 137:
! 138: /*
! 139: * Assume the database starts with some integers.
! 140: * Assume they are numbered starting from 0, increasing.
! 141: * Get a pointer to one with the number "offset".
! 142: */
! 143: int32_t *
! 144: dbm_getint(int32_t offset)
! 145: {
! 146: return (int32_t *)dbm_base + offset;
! 147: }
! 148:
! 149: /*
! 150: * The reverse of dbm_get().
! 151: * Take pointer into the database file
! 152: * and convert it to the raw integer
! 153: * that would be used to refer to that place in the file.
! 154: */
! 155: int32_t
! 156: dbm_addr(const void *p)
! 157: {
! 158: return htobe32((char *)p - dbm_base);
! 159: }
! 160:
! 161: int
! 162: dbm_match(const struct dbm_match *match, const char *str)
! 163: {
! 164: switch (match->type) {
! 165: case DBM_EXACT:
! 166: return strcmp(str, match->str) == 0;
! 167: case DBM_SUB:
! 168: return strcasestr(str, match->str) != NULL;
! 169: case DBM_REGEX:
! 170: return regexec(match->re, str, 0, NULL, 0) == 0;
! 171: default:
! 172: abort();
! 173: }
! 174: }
CVSweb