1*84d9c625SLionel Sambuc /* $NetBSD: rec_open.c,v 1.20 2013/12/01 00:22:48 christos Exp $ */
22639ae9bSBen Gras
32639ae9bSBen Gras /*-
42639ae9bSBen Gras * Copyright (c) 1990, 1993, 1994
52639ae9bSBen Gras * The Regents of the University of California. All rights reserved.
62639ae9bSBen Gras *
72639ae9bSBen Gras * This code is derived from software contributed to Berkeley by
82639ae9bSBen Gras * Mike Olson.
92639ae9bSBen Gras *
102639ae9bSBen Gras * Redistribution and use in source and binary forms, with or without
112639ae9bSBen Gras * modification, are permitted provided that the following conditions
122639ae9bSBen Gras * are met:
132639ae9bSBen Gras * 1. Redistributions of source code must retain the above copyright
142639ae9bSBen Gras * notice, this list of conditions and the following disclaimer.
152639ae9bSBen Gras * 2. Redistributions in binary form must reproduce the above copyright
162639ae9bSBen Gras * notice, this list of conditions and the following disclaimer in the
172639ae9bSBen Gras * documentation and/or other materials provided with the distribution.
182639ae9bSBen Gras * 3. Neither the name of the University nor the names of its contributors
192639ae9bSBen Gras * may be used to endorse or promote products derived from this software
202639ae9bSBen Gras * without specific prior written permission.
212639ae9bSBen Gras *
222639ae9bSBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232639ae9bSBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242639ae9bSBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252639ae9bSBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262639ae9bSBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272639ae9bSBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282639ae9bSBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292639ae9bSBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302639ae9bSBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312639ae9bSBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322639ae9bSBen Gras * SUCH DAMAGE.
332639ae9bSBen Gras */
342639ae9bSBen Gras
352639ae9bSBen Gras #if HAVE_NBTOOL_CONFIG_H
362639ae9bSBen Gras #include "nbtool_config.h"
372639ae9bSBen Gras #endif
382639ae9bSBen Gras
392639ae9bSBen Gras #include <sys/cdefs.h>
40*84d9c625SLionel Sambuc __RCSID("$NetBSD: rec_open.c,v 1.20 2013/12/01 00:22:48 christos Exp $");
412639ae9bSBen Gras
422639ae9bSBen Gras #include "namespace.h"
432639ae9bSBen Gras #include <sys/types.h>
442639ae9bSBen Gras #include <sys/mman.h>
452639ae9bSBen Gras #include <sys/stat.h>
462639ae9bSBen Gras
472639ae9bSBen Gras #include <assert.h>
482639ae9bSBen Gras #include <errno.h>
492639ae9bSBen Gras #include <fcntl.h>
502639ae9bSBen Gras #include <limits.h>
512639ae9bSBen Gras #include <stddef.h>
522639ae9bSBen Gras #include <stdio.h>
532639ae9bSBen Gras #include <unistd.h>
542639ae9bSBen Gras
552639ae9bSBen Gras #include <db.h>
562639ae9bSBen Gras #include "recno.h"
572639ae9bSBen Gras
582639ae9bSBen Gras DB *
__rec_open(const char * fname,int flags,mode_t mode,const RECNOINFO * openinfo,int dflags)592639ae9bSBen Gras __rec_open(const char *fname, int flags, mode_t mode, const RECNOINFO *openinfo,
602639ae9bSBen Gras int dflags)
612639ae9bSBen Gras {
622639ae9bSBen Gras BTREE *t;
632639ae9bSBen Gras BTREEINFO btopeninfo;
642639ae9bSBen Gras DB *dbp;
652639ae9bSBen Gras PAGE *h;
662639ae9bSBen Gras struct stat sb;
672639ae9bSBen Gras int rfd = -1; /* pacify gcc */
682639ae9bSBen Gras int sverrno;
692639ae9bSBen Gras
702639ae9bSBen Gras dbp = NULL;
712639ae9bSBen Gras /* Open the user's file -- if this fails, we're done. */
722639ae9bSBen Gras if (fname != NULL) {
73*84d9c625SLionel Sambuc if ((rfd = __dbopen(fname, flags, mode, NULL)) == -1)
74f14fb602SLionel Sambuc return NULL;
752639ae9bSBen Gras }
762639ae9bSBen Gras
772639ae9bSBen Gras /* Create a btree in memory (backed by disk). */
782639ae9bSBen Gras if (openinfo) {
792639ae9bSBen Gras if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
802639ae9bSBen Gras goto einval;
812639ae9bSBen Gras btopeninfo.flags = 0;
822639ae9bSBen Gras btopeninfo.cachesize = openinfo->cachesize;
832639ae9bSBen Gras btopeninfo.maxkeypage = 0;
842639ae9bSBen Gras btopeninfo.minkeypage = 0;
852639ae9bSBen Gras btopeninfo.psize = openinfo->psize;
862639ae9bSBen Gras btopeninfo.compare = NULL;
872639ae9bSBen Gras btopeninfo.prefix = NULL;
882639ae9bSBen Gras btopeninfo.lorder = openinfo->lorder;
892639ae9bSBen Gras dbp = __bt_open(openinfo->bfname,
902639ae9bSBen Gras O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
912639ae9bSBen Gras } else
922639ae9bSBen Gras dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags);
932639ae9bSBen Gras if (dbp == NULL)
942639ae9bSBen Gras goto err;
952639ae9bSBen Gras
962639ae9bSBen Gras /*
972639ae9bSBen Gras * Some fields in the tree structure are recno specific. Fill them
982639ae9bSBen Gras * in and make the btree structure look like a recno structure. We
992639ae9bSBen Gras * don't change the bt_ovflsize value, it's close enough and slightly
1002639ae9bSBen Gras * bigger.
1012639ae9bSBen Gras */
1022639ae9bSBen Gras t = dbp->internal;
1032639ae9bSBen Gras if (openinfo) {
1042639ae9bSBen Gras if (openinfo->flags & R_FIXEDLEN) {
1052639ae9bSBen Gras F_SET(t, R_FIXLEN);
1062639ae9bSBen Gras t->bt_reclen = openinfo->reclen;
1072639ae9bSBen Gras if (t->bt_reclen == 0)
1082639ae9bSBen Gras goto einval;
1092639ae9bSBen Gras }
1102639ae9bSBen Gras t->bt_bval = openinfo->bval;
1112639ae9bSBen Gras } else
1122639ae9bSBen Gras t->bt_bval = '\n';
1132639ae9bSBen Gras
1142639ae9bSBen Gras F_SET(t, R_RECNO);
1152639ae9bSBen Gras if (fname == NULL)
1162639ae9bSBen Gras F_SET(t, R_EOF | R_INMEM);
1172639ae9bSBen Gras else
1182639ae9bSBen Gras t->bt_rfd = rfd;
1192639ae9bSBen Gras
1202639ae9bSBen Gras if (fname != NULL) {
1212639ae9bSBen Gras /*
1222639ae9bSBen Gras * In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
1232639ae9bSBen Gras * Unfortunately, that's not portable, so we use lseek
1242639ae9bSBen Gras * and check the errno values.
1252639ae9bSBen Gras */
1262639ae9bSBen Gras errno = 0;
1272639ae9bSBen Gras if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
1282639ae9bSBen Gras switch (flags & O_ACCMODE) {
1292639ae9bSBen Gras case O_RDONLY:
1302639ae9bSBen Gras F_SET(t, R_RDONLY);
1312639ae9bSBen Gras break;
1322639ae9bSBen Gras default:
1332639ae9bSBen Gras goto einval;
1342639ae9bSBen Gras }
1352639ae9bSBen Gras slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
1362639ae9bSBen Gras goto err;
1372639ae9bSBen Gras F_SET(t, R_CLOSEFP);
1382639ae9bSBen Gras t->bt_irec =
1392639ae9bSBen Gras F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
1402639ae9bSBen Gras } else {
1412639ae9bSBen Gras switch (flags & O_ACCMODE) {
1422639ae9bSBen Gras case O_RDONLY:
1432639ae9bSBen Gras F_SET(t, R_RDONLY);
1442639ae9bSBen Gras break;
1452639ae9bSBen Gras case O_RDWR:
1462639ae9bSBen Gras break;
1472639ae9bSBen Gras default:
1482639ae9bSBen Gras goto einval;
1492639ae9bSBen Gras }
1502639ae9bSBen Gras
1512639ae9bSBen Gras if (fstat(rfd, &sb))
1522639ae9bSBen Gras goto err;
1532639ae9bSBen Gras /*
1542639ae9bSBen Gras * Kluge -- we'd like to test to see if the file is too
1552639ae9bSBen Gras * big to mmap. Since, we don't know what size or type
1562639ae9bSBen Gras * off_t's or size_t's are, what the largest unsigned
1572639ae9bSBen Gras * integral type is, or what random insanity the local
1582639ae9bSBen Gras * C compiler will perpetrate, doing the comparison in
1592639ae9bSBen Gras * a portable way is flatly impossible. Hope that mmap
1602639ae9bSBen Gras * fails if the file is too large.
1612639ae9bSBen Gras */
1622639ae9bSBen Gras if (sb.st_size == 0)
1632639ae9bSBen Gras F_SET(t, R_EOF);
1642639ae9bSBen Gras else {
1652639ae9bSBen Gras #ifdef MMAP_NOT_AVAILABLE
1662639ae9bSBen Gras /*
1672639ae9bSBen Gras * XXX
1682639ae9bSBen Gras * Mmap doesn't work correctly on many current
1692639ae9bSBen Gras * systems. In particular, it can fail subtly,
1702639ae9bSBen Gras * with cache coherency problems. Don't use it
1712639ae9bSBen Gras * for now.
1722639ae9bSBen Gras */
1732639ae9bSBen Gras t->bt_msize = sb.st_size;
1742639ae9bSBen Gras if ((t->bt_smap = mmap(NULL, t->bt_msize,
1752639ae9bSBen Gras PROT_READ, MAP_FILE | MAP_PRIVATE, rfd,
1762639ae9bSBen Gras (off_t)0)) == (caddr_t)-1)
1772639ae9bSBen Gras goto slow;
1782639ae9bSBen Gras t->bt_cmap = t->bt_smap;
1792639ae9bSBen Gras t->bt_emap = t->bt_smap + sb.st_size;
1802639ae9bSBen Gras t->bt_irec = F_ISSET(t, R_FIXLEN) ?
1812639ae9bSBen Gras __rec_fmap : __rec_vmap;
1822639ae9bSBen Gras F_SET(t, R_MEMMAPPED);
1832639ae9bSBen Gras #else
1842639ae9bSBen Gras goto slow;
1852639ae9bSBen Gras #endif
1862639ae9bSBen Gras }
1872639ae9bSBen Gras }
1882639ae9bSBen Gras }
1892639ae9bSBen Gras
1902639ae9bSBen Gras /* Use the recno routines. */
1912639ae9bSBen Gras dbp->close = __rec_close;
1922639ae9bSBen Gras dbp->del = __rec_delete;
1932639ae9bSBen Gras dbp->fd = __rec_fd;
1942639ae9bSBen Gras dbp->get = __rec_get;
1952639ae9bSBen Gras dbp->put = __rec_put;
1962639ae9bSBen Gras dbp->seq = __rec_seq;
1972639ae9bSBen Gras dbp->sync = __rec_sync;
1982639ae9bSBen Gras
1992639ae9bSBen Gras /* If the root page was created, reset the flags. */
2002639ae9bSBen Gras if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
2012639ae9bSBen Gras goto err;
2022639ae9bSBen Gras if ((h->flags & P_TYPE) == P_BLEAF) {
2032639ae9bSBen Gras F_CLR(h, P_TYPE);
2042639ae9bSBen Gras F_SET(h, P_RLEAF);
2052639ae9bSBen Gras mpool_put(t->bt_mp, h, MPOOL_DIRTY);
2062639ae9bSBen Gras } else
2072639ae9bSBen Gras mpool_put(t->bt_mp, h, 0);
2082639ae9bSBen Gras
2092639ae9bSBen Gras if (openinfo && openinfo->flags & R_SNAPSHOT &&
2102639ae9bSBen Gras !F_ISSET(t, R_EOF | R_INMEM) &&
2112639ae9bSBen Gras t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
2122639ae9bSBen Gras goto err;
2132639ae9bSBen Gras return (dbp);
2142639ae9bSBen Gras
2152639ae9bSBen Gras einval: errno = EINVAL;
2162639ae9bSBen Gras err: sverrno = errno;
2172639ae9bSBen Gras if (dbp != NULL)
2182639ae9bSBen Gras (void)__bt_close(dbp);
2192639ae9bSBen Gras if (fname != NULL)
2202639ae9bSBen Gras (void)close(rfd);
2212639ae9bSBen Gras errno = sverrno;
2222639ae9bSBen Gras return (NULL);
2232639ae9bSBen Gras }
2242639ae9bSBen Gras
2252639ae9bSBen Gras int
__rec_fd(const DB * dbp)2262639ae9bSBen Gras __rec_fd(const DB *dbp)
2272639ae9bSBen Gras {
2282639ae9bSBen Gras BTREE *t;
2292639ae9bSBen Gras
2302639ae9bSBen Gras t = dbp->internal;
2312639ae9bSBen Gras
2322639ae9bSBen Gras /* Toss any page pinned across calls. */
2332639ae9bSBen Gras if (t->bt_pinned != NULL) {
2342639ae9bSBen Gras mpool_put(t->bt_mp, t->bt_pinned, 0);
2352639ae9bSBen Gras t->bt_pinned = NULL;
2362639ae9bSBen Gras }
2372639ae9bSBen Gras
2382639ae9bSBen Gras /* In-memory database can't have a file descriptor. */
2392639ae9bSBen Gras if (F_ISSET(t, R_INMEM)) {
2402639ae9bSBen Gras errno = ENOENT;
2412639ae9bSBen Gras return (-1);
2422639ae9bSBen Gras }
2432639ae9bSBen Gras return (t->bt_rfd);
2442639ae9bSBen Gras }
245