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