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