rec_open.c revision 56698
11573Srgrimes/*-
214272Spst * Copyright (c) 1990, 1993, 1994
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Mike Olson.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 3. All advertising materials mentioning features or use of this software
171573Srgrimes *    must display the following acknowledgement:
181573Srgrimes *	This product includes software developed by the University of
191573Srgrimes *	California, Berkeley and its contributors.
201573Srgrimes * 4. Neither the name of the University nor the names of its contributors
211573Srgrimes *    may be used to endorse or promote products derived from this software
221573Srgrimes *    without specific prior written permission.
231573Srgrimes *
241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341573Srgrimes * SUCH DAMAGE.
3555837Sjasone *
3655837Sjasone * $FreeBSD: head/lib/libc/db/recno/rec_open.c 56698 2000-01-27 23:07:25Z jasone $
371573Srgrimes */
381573Srgrimes
391573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
4014272Spststatic char sccsid[] = "@(#)rec_open.c	8.10 (Berkeley) 9/1/94";
411573Srgrimes#endif /* LIBC_SCCS and not lint */
421573Srgrimes
431573Srgrimes#include <sys/types.h>
441573Srgrimes#include <sys/mman.h>
451573Srgrimes#include <sys/stat.h>
461573Srgrimes
471573Srgrimes#include <errno.h>
481573Srgrimes#include <fcntl.h>
491573Srgrimes#include <limits.h>
501573Srgrimes#include <stddef.h>
511573Srgrimes#include <stdio.h>
521573Srgrimes#include <unistd.h>
531573Srgrimes
541573Srgrimes#include <db.h>
551573Srgrimes#include "recno.h"
561573Srgrimes
571573SrgrimesDB *
581573Srgrimes__rec_open(fname, flags, mode, openinfo, dflags)
591573Srgrimes	const char *fname;
601573Srgrimes	int flags, mode, dflags;
611573Srgrimes	const RECNOINFO *openinfo;
621573Srgrimes{
631573Srgrimes	BTREE *t;
641573Srgrimes	BTREEINFO btopeninfo;
651573Srgrimes	DB *dbp;
661573Srgrimes	PAGE *h;
671573Srgrimes	struct stat sb;
681573Srgrimes	int rfd, sverrno;
691573Srgrimes
701573Srgrimes	/* Open the user's file -- if this fails, we're done. */
7156698Sjasone	if (fname != NULL && (rfd = _open(fname, flags, mode)) < 0)
721573Srgrimes		return (NULL);
731573Srgrimes
741573Srgrimes	/* Create a btree in memory (backed by disk). */
751573Srgrimes	dbp = NULL;
761573Srgrimes	if (openinfo) {
771573Srgrimes		if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
781573Srgrimes			goto einval;
791573Srgrimes		btopeninfo.flags = 0;
801573Srgrimes		btopeninfo.cachesize = openinfo->cachesize;
811573Srgrimes		btopeninfo.maxkeypage = 0;
821573Srgrimes		btopeninfo.minkeypage = 0;
831573Srgrimes		btopeninfo.psize = openinfo->psize;
841573Srgrimes		btopeninfo.compare = NULL;
851573Srgrimes		btopeninfo.prefix = NULL;
861573Srgrimes		btopeninfo.lorder = openinfo->lorder;
871573Srgrimes		dbp = __bt_open(openinfo->bfname,
881573Srgrimes		    O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
891573Srgrimes	} else
901573Srgrimes		dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags);
911573Srgrimes	if (dbp == NULL)
921573Srgrimes		goto err;
931573Srgrimes
941573Srgrimes	/*
951573Srgrimes	 * Some fields in the tree structure are recno specific.  Fill them
961573Srgrimes	 * in and make the btree structure look like a recno structure.  We
971573Srgrimes	 * don't change the bt_ovflsize value, it's close enough and slightly
981573Srgrimes	 * bigger.
991573Srgrimes	 */
1001573Srgrimes	t = dbp->internal;
1011573Srgrimes	if (openinfo) {
1021573Srgrimes		if (openinfo->flags & R_FIXEDLEN) {
10314272Spst			F_SET(t, R_FIXLEN);
1041573Srgrimes			t->bt_reclen = openinfo->reclen;
1051573Srgrimes			if (t->bt_reclen == 0)
1061573Srgrimes				goto einval;
1071573Srgrimes		}
1081573Srgrimes		t->bt_bval = openinfo->bval;
1091573Srgrimes	} else
1101573Srgrimes		t->bt_bval = '\n';
1111573Srgrimes
11214272Spst	F_SET(t, R_RECNO);
1131573Srgrimes	if (fname == NULL)
11414272Spst		F_SET(t, R_EOF | R_INMEM);
1151573Srgrimes	else
1161573Srgrimes		t->bt_rfd = rfd;
1171573Srgrimes
1181573Srgrimes	if (fname != NULL) {
1191573Srgrimes		/*
1201573Srgrimes		 * In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
1211573Srgrimes		 * Unfortunately, that's not portable, so we use lseek
1221573Srgrimes		 * and check the errno values.
1231573Srgrimes		 */
1241573Srgrimes		errno = 0;
1251573Srgrimes		if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
1261573Srgrimes			switch (flags & O_ACCMODE) {
1271573Srgrimes			case O_RDONLY:
12814272Spst				F_SET(t, R_RDONLY);
1291573Srgrimes				break;
1301573Srgrimes			default:
1311573Srgrimes				goto einval;
1321573Srgrimes			}
1331573Srgrimesslow:			if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
1341573Srgrimes				goto err;
13514272Spst			F_SET(t, R_CLOSEFP);
1361573Srgrimes			t->bt_irec =
13714272Spst			    F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
1381573Srgrimes		} else {
1391573Srgrimes			switch (flags & O_ACCMODE) {
1401573Srgrimes			case O_RDONLY:
14114272Spst				F_SET(t, R_RDONLY);
1421573Srgrimes				break;
1431573Srgrimes			case O_RDWR:
1441573Srgrimes				break;
1451573Srgrimes			default:
1461573Srgrimes				goto einval;
1471573Srgrimes			}
1481573Srgrimes
1491573Srgrimes			if (fstat(rfd, &sb))
1501573Srgrimes				goto err;
1511573Srgrimes			/*
1521573Srgrimes			 * Kluge -- we'd like to test to see if the file is too
1531573Srgrimes			 * big to mmap.  Since, we don't know what size or type
1541573Srgrimes			 * off_t's or size_t's are, what the largest unsigned
1551573Srgrimes			 * integral type is, or what random insanity the local
1561573Srgrimes			 * C compiler will perpetrate, doing the comparison in
1571573Srgrimes			 * a portable way is flatly impossible.  Hope that mmap
1581573Srgrimes			 * fails if the file is too large.
1591573Srgrimes			 */
1601573Srgrimes			if (sb.st_size == 0)
16114272Spst				F_SET(t, R_EOF);
1621573Srgrimes			else {
16314272Spst#ifdef MMAP_NOT_AVAILABLE
16414272Spst				/*
16514272Spst				 * XXX
16614272Spst				 * Mmap doesn't work correctly on many current
16714272Spst				 * systems.  In particular, it can fail subtly,
16814272Spst				 * with cache coherency problems.  Don't use it
16914272Spst				 * for now.
17014272Spst				 */
1711573Srgrimes				t->bt_msize = sb.st_size;
1721573Srgrimes				if ((t->bt_smap = mmap(NULL, t->bt_msize,
1731573Srgrimes				    PROT_READ, MAP_PRIVATE, rfd,
17421786Salex				    (off_t)0)) == MAP_FAILED)
1751573Srgrimes					goto slow;
1761573Srgrimes				t->bt_cmap = t->bt_smap;
1771573Srgrimes				t->bt_emap = t->bt_smap + sb.st_size;
17814272Spst				t->bt_irec = F_ISSET(t, R_FIXLEN) ?
1791573Srgrimes				    __rec_fmap : __rec_vmap;
18014272Spst				F_SET(t, R_MEMMAPPED);
18114272Spst#else
18214272Spst				goto slow;
18314272Spst#endif
1841573Srgrimes			}
1851573Srgrimes		}
1861573Srgrimes	}
1871573Srgrimes
1881573Srgrimes	/* Use the recno routines. */
1891573Srgrimes	dbp->close = __rec_close;
1901573Srgrimes	dbp->del = __rec_delete;
1911573Srgrimes	dbp->fd = __rec_fd;
1921573Srgrimes	dbp->get = __rec_get;
1931573Srgrimes	dbp->put = __rec_put;
1941573Srgrimes	dbp->seq = __rec_seq;
1951573Srgrimes	dbp->sync = __rec_sync;
1961573Srgrimes
1971573Srgrimes	/* If the root page was created, reset the flags. */
1981573Srgrimes	if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
1991573Srgrimes		goto err;
2001573Srgrimes	if ((h->flags & P_TYPE) == P_BLEAF) {
20114272Spst		F_CLR(h, P_TYPE);
20214272Spst		F_SET(h, P_RLEAF);
2031573Srgrimes		mpool_put(t->bt_mp, h, MPOOL_DIRTY);
2041573Srgrimes	} else
2051573Srgrimes		mpool_put(t->bt_mp, h, 0);
2061573Srgrimes
2071573Srgrimes	if (openinfo && openinfo->flags & R_SNAPSHOT &&
20814272Spst	    !F_ISSET(t, R_EOF | R_INMEM) &&
2091573Srgrimes	    t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
2101573Srgrimes                goto err;
2111573Srgrimes	return (dbp);
2121573Srgrimes
2131573Srgrimeseinval:	errno = EINVAL;
2141573Srgrimeserr:	sverrno = errno;
2151573Srgrimes	if (dbp != NULL)
2161573Srgrimes		(void)__bt_close(dbp);
2171573Srgrimes	if (fname != NULL)
21856698Sjasone		(void)_close(rfd);
2191573Srgrimes	errno = sverrno;
2201573Srgrimes	return (NULL);
2211573Srgrimes}
2221573Srgrimes
2231573Srgrimesint
2241573Srgrimes__rec_fd(dbp)
2251573Srgrimes	const DB *dbp;
2261573Srgrimes{
2271573Srgrimes	BTREE *t;
2281573Srgrimes
2291573Srgrimes	t = dbp->internal;
2301573Srgrimes
2311573Srgrimes	/* Toss any page pinned across calls. */
2321573Srgrimes	if (t->bt_pinned != NULL) {
2331573Srgrimes		mpool_put(t->bt_mp, t->bt_pinned, 0);
2341573Srgrimes		t->bt_pinned = NULL;
2351573Srgrimes	}
2361573Srgrimes
2371573Srgrimes	/* In-memory database can't have a file descriptor. */
23814272Spst	if (F_ISSET(t, R_INMEM)) {
2391573Srgrimes		errno = ENOENT;
2401573Srgrimes		return (-1);
2411573Srgrimes	}
2421573Srgrimes	return (t->bt_rfd);
2431573Srgrimes}
244