xref: /minix3/lib/libc/db/recno/rec_open.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
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