rec_open.c revision 189327
156893Sfenner/*-
256893Sfenner * Copyright (c) 1990, 1993, 1994
356893Sfenner *	The Regents of the University of California.  All rights reserved.
456893Sfenner *
556893Sfenner * This code is derived from software contributed to Berkeley by
656893Sfenner * Mike Olson.
756893Sfenner *
856893Sfenner * Redistribution and use in source and binary forms, with or without
956893Sfenner * modification, are permitted provided that the following conditions
1056893Sfenner * are met:
1156893Sfenner * 1. Redistributions of source code must retain the above copyright
1256893Sfenner *    notice, this list of conditions and the following disclaimer.
1356893Sfenner * 2. Redistributions in binary form must reproduce the above copyright
1456893Sfenner *    notice, this list of conditions and the following disclaimer in the
1556893Sfenner *    documentation and/or other materials provided with the distribution.
1656893Sfenner * 4. Neither the name of the University nor the names of its contributors
1756893Sfenner *    may be used to endorse or promote products derived from this software
1856893Sfenner *    without specific prior written permission.
1956893Sfenner *
2056893Sfenner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2175115Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2256893Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2356893Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2456893Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25127668Sbms * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26190207Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2756893Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2856893Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2956893Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3056893Sfenner * SUCH DAMAGE.
3156893Sfenner */
3256893Sfenner
33127668Sbms#if defined(LIBC_SCCS) && !defined(lint)
34127668Sbmsstatic char sccsid[] = "@(#)rec_open.c	8.10 (Berkeley) 9/1/94";
3556893Sfenner#endif /* LIBC_SCCS and not lint */
3656893Sfenner#include <sys/cdefs.h>
3756893Sfenner__FBSDID("$FreeBSD: head/lib/libc/db/recno/rec_open.c 189327 2009-03-04 00:58:04Z delphij $");
3856893Sfenner
39111726Sfenner#include "namespace.h"
4056893Sfenner#include <sys/types.h>
4156893Sfenner#include <sys/mman.h>
4256893Sfenner#include <sys/stat.h>
4398524Sfenner
4498524Sfenner#include <errno.h>
4598524Sfenner#include <fcntl.h>
4698524Sfenner#include <limits.h>
4798524Sfenner#include <stddef.h>
4898524Sfenner#include <stdio.h>
4998524Sfenner#include <unistd.h>
5098524Sfenner#include "un-namespace.h"
5198524Sfenner
5298524Sfenner#include <db.h>
5398524Sfenner#include "recno.h"
5498524Sfenner
5598524SfennerDB *
5698524Sfenner__rec_open(const char *fname, int flags, int mode, const RECNOINFO *openinfo,
5798524Sfenner    int dflags)
5898524Sfenner{
5998524Sfenner	BTREE *t;
6098524Sfenner	BTREEINFO btopeninfo;
6198524Sfenner	DB *dbp;
6298524Sfenner	PAGE *h;
6398524Sfenner	struct stat sb;
6498524Sfenner	int rfd, sverrno;
6598524Sfenner
6698524Sfenner	/* Open the user's file -- if this fails, we're done. */
6798524Sfenner	if (fname != NULL && (rfd = _open(fname, flags, mode)) < 0)
6898524Sfenner		return (NULL);
6998524Sfenner
7098524Sfenner	/* Create a btree in memory (backed by disk). */
7198524Sfenner	dbp = NULL;
7298524Sfenner	if (openinfo) {
7398524Sfenner		if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
7456893Sfenner			goto einval;
7556893Sfenner		btopeninfo.flags = 0;
7698524Sfenner		btopeninfo.cachesize = openinfo->cachesize;
7798524Sfenner		btopeninfo.maxkeypage = 0;
7898524Sfenner		btopeninfo.minkeypage = 0;
7998524Sfenner		btopeninfo.psize = openinfo->psize;
8098524Sfenner		btopeninfo.compare = NULL;
8198524Sfenner		btopeninfo.prefix = NULL;
8298524Sfenner		btopeninfo.lorder = openinfo->lorder;
8398524Sfenner		dbp = __bt_open(openinfo->bfname,
8498524Sfenner		    O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
8598524Sfenner	} else
8698524Sfenner		dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags);
8798524Sfenner	if (dbp == NULL)
8898524Sfenner		goto err;
8998524Sfenner
9098524Sfenner	/*
9198524Sfenner	 * Some fields in the tree structure are recno specific.  Fill them
9298524Sfenner	 * in and make the btree structure look like a recno structure.  We
9398524Sfenner	 * don't change the bt_ovflsize value, it's close enough and slightly
9498524Sfenner	 * bigger.
9598524Sfenner	 */
9698524Sfenner	t = dbp->internal;
9798524Sfenner	if (openinfo) {
9898524Sfenner		if (openinfo->flags & R_FIXEDLEN) {
9998524Sfenner			F_SET(t, R_FIXLEN);
10098524Sfenner			t->bt_reclen = openinfo->reclen;
10198524Sfenner			if (t->bt_reclen == 0)
10298524Sfenner				goto einval;
10398524Sfenner		}
10498524Sfenner		t->bt_bval = openinfo->bval;
10598524Sfenner	} else
10698524Sfenner		t->bt_bval = '\n';
10798524Sfenner
10898524Sfenner	F_SET(t, R_RECNO);
10998524Sfenner	if (fname == NULL)
11098524Sfenner		F_SET(t, R_EOF | R_INMEM);
11198524Sfenner	else
11298524Sfenner		t->bt_rfd = rfd;
11398524Sfenner
11498524Sfenner	if (fname != NULL) {
11598524Sfenner		/*
11698524Sfenner		 * In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
11756893Sfenner		 * Unfortunately, that's not portable, so we use lseek
11898524Sfenner		 * and check the errno values.
11998524Sfenner		 */
12098524Sfenner		errno = 0;
12198524Sfenner		if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
12298524Sfenner			switch (flags & O_ACCMODE) {
12398524Sfenner			case O_RDONLY:
12498524Sfenner				F_SET(t, R_RDONLY);
12598524Sfenner				break;
12698524Sfenner			default:
12798524Sfenner				goto einval;
12898524Sfenner			}
12998524Sfennerslow:			if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
13098524Sfenner				goto err;
13198524Sfenner			F_SET(t, R_CLOSEFP);
13298524Sfenner			t->bt_irec =
13398524Sfenner			    F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
13498524Sfenner		} else {
13598524Sfenner			switch (flags & O_ACCMODE) {
13698524Sfenner			case O_RDONLY:
13798524Sfenner				F_SET(t, R_RDONLY);
13898524Sfenner				break;
139127668Sbms			case O_RDWR:
14098524Sfenner				break;
14198524Sfenner			default:
14298524Sfenner				goto einval;
14398524Sfenner			}
14498524Sfenner
14598524Sfenner			if (_fstat(rfd, &sb))
146127668Sbms				goto err;
147127668Sbms			/*
148127668Sbms			 * Kluge -- we'd like to test to see if the file is too
14998524Sfenner			 * big to mmap.  Since, we don't know what size or type
150127668Sbms			 * off_t's or size_t's are, what the largest unsigned
15198524Sfenner			 * integral type is, or what random insanity the local
15298524Sfenner			 * C compiler will perpetrate, doing the comparison in
15398524Sfenner			 * a portable way is flatly impossible.  Hope that mmap
154127668Sbms			 * fails if the file is too large.
155127668Sbms			 */
15698524Sfenner			if (sb.st_size == 0)
157127668Sbms				F_SET(t, R_EOF);
158127668Sbms			else {
159127668Sbms#ifdef MMAP_NOT_AVAILABLE
16098524Sfenner				/*
16156893Sfenner				 * XXX
16256893Sfenner				 * Mmap doesn't work correctly on many current
16398524Sfenner				 * systems.  In particular, it can fail subtly,
16498524Sfenner				 * with cache coherency problems.  Don't use it
16598524Sfenner				 * for now.
16698524Sfenner				 */
16798524Sfenner				t->bt_msize = sb.st_size;
16898524Sfenner				if ((t->bt_smap = mmap(NULL, t->bt_msize,
16998524Sfenner				    PROT_READ, MAP_PRIVATE, rfd,
17098524Sfenner				    (off_t)0)) == MAP_FAILED)
17198524Sfenner					goto slow;
17298524Sfenner				t->bt_cmap = t->bt_smap;
17398524Sfenner				t->bt_emap = t->bt_smap + sb.st_size;
17498524Sfenner				t->bt_irec = F_ISSET(t, R_FIXLEN) ?
17598524Sfenner				    __rec_fmap : __rec_vmap;
17698524Sfenner				F_SET(t, R_MEMMAPPED);
17798524Sfenner#else
17898524Sfenner				goto slow;
17998524Sfenner#endif
18098524Sfenner			}
18198524Sfenner		}
18298524Sfenner	}
18398524Sfenner
18456893Sfenner	/* Use the recno routines. */
18556893Sfenner	dbp->close = __rec_close;
18656893Sfenner	dbp->del = __rec_delete;
18756893Sfenner	dbp->fd = __rec_fd;
18856893Sfenner	dbp->get = __rec_get;
18956893Sfenner	dbp->put = __rec_put;
19056893Sfenner	dbp->seq = __rec_seq;
19156893Sfenner	dbp->sync = __rec_sync;
19256893Sfenner
19356893Sfenner	/* If the root page was created, reset the flags. */
19456893Sfenner	if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
19556893Sfenner		goto err;
19656893Sfenner	if ((h->flags & P_TYPE) == P_BLEAF) {
19756893Sfenner		F_CLR(h, P_TYPE);
19856893Sfenner		F_SET(h, P_RLEAF);
19956893Sfenner		mpool_put(t->bt_mp, h, MPOOL_DIRTY);
20056893Sfenner	} else
20156893Sfenner		mpool_put(t->bt_mp, h, 0);
20256893Sfenner
20356893Sfenner	if (openinfo && openinfo->flags & R_SNAPSHOT &&
20456893Sfenner	    !F_ISSET(t, R_EOF | R_INMEM) &&
20556893Sfenner	    t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
20656893Sfenner		goto err;
20756893Sfenner	return (dbp);
20856893Sfenner
20956893Sfennereinval:	errno = EINVAL;
21056893Sfennererr:	sverrno = errno;
21156893Sfenner	if (dbp != NULL)
21256893Sfenner		(void)__bt_close(dbp);
21356893Sfenner	if (fname != NULL)
21456893Sfenner		(void)_close(rfd);
21556893Sfenner	errno = sverrno;
21656893Sfenner	return (NULL);
21756893Sfenner}
21856893Sfenner
21956893Sfennerint
22056893Sfenner__rec_fd(const DB *dbp)
22156893Sfenner{
22256893Sfenner	BTREE *t;
22356893Sfenner
22456893Sfenner	t = dbp->internal;
22556893Sfenner
22656893Sfenner	/* Toss any page pinned across calls. */
22756893Sfenner	if (t->bt_pinned != NULL) {
22856893Sfenner		mpool_put(t->bt_mp, t->bt_pinned, 0);
22956893Sfenner		t->bt_pinned = NULL;
23056893Sfenner	}
23156893Sfenner
23256893Sfenner	/* In-memory database can't have a file descriptor. */
23356893Sfenner	if (F_ISSET(t, R_INMEM)) {
23456893Sfenner		errno = ENOENT;
23556893Sfenner		return (-1);
236127668Sbms	}
23756893Sfenner	return (t->bt_rfd);
23856893Sfenner}
239127668Sbms