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 * 4. Neither the name of the University nor the names of its contributors 171573Srgrimes * may be used to endorse or promote products derived from this software 181573Srgrimes * without specific prior written permission. 191573Srgrimes * 201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301573Srgrimes * SUCH DAMAGE. 311573Srgrimes */ 321573Srgrimes 331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 3414272Spststatic char sccsid[] = "@(#)rec_open.c 8.10 (Berkeley) 9/1/94"; 351573Srgrimes#endif /* LIBC_SCCS and not lint */ 3692986Sobrien#include <sys/cdefs.h> 3792986Sobrien__FBSDID("$FreeBSD$"); 381573Srgrimes 3971579Sdeischen#include "namespace.h" 401573Srgrimes#include <sys/types.h> 411573Srgrimes#include <sys/mman.h> 421573Srgrimes#include <sys/stat.h> 431573Srgrimes 441573Srgrimes#include <errno.h> 451573Srgrimes#include <fcntl.h> 461573Srgrimes#include <limits.h> 471573Srgrimes#include <stddef.h> 481573Srgrimes#include <stdio.h> 491573Srgrimes#include <unistd.h> 5071579Sdeischen#include "un-namespace.h" 511573Srgrimes 521573Srgrimes#include <db.h> 531573Srgrimes#include "recno.h" 541573Srgrimes 551573SrgrimesDB * 56189291Sdelphij__rec_open(const char *fname, int flags, int mode, const RECNOINFO *openinfo, 57189291Sdelphij int dflags) 581573Srgrimes{ 591573Srgrimes BTREE *t; 601573Srgrimes BTREEINFO btopeninfo; 611573Srgrimes DB *dbp; 621573Srgrimes PAGE *h; 631573Srgrimes struct stat sb; 641573Srgrimes int rfd, sverrno; 651573Srgrimes 661573Srgrimes /* Open the user's file -- if this fails, we're done. */ 67287761Sjilles if (fname != NULL && (rfd = _open(fname, flags | O_CLOEXEC, mode)) < 0) 681573Srgrimes return (NULL); 691573Srgrimes 701573Srgrimes /* Create a btree in memory (backed by disk). */ 711573Srgrimes dbp = NULL; 721573Srgrimes if (openinfo) { 731573Srgrimes if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT)) 741573Srgrimes goto einval; 751573Srgrimes btopeninfo.flags = 0; 761573Srgrimes btopeninfo.cachesize = openinfo->cachesize; 771573Srgrimes btopeninfo.maxkeypage = 0; 781573Srgrimes btopeninfo.minkeypage = 0; 791573Srgrimes btopeninfo.psize = openinfo->psize; 801573Srgrimes btopeninfo.compare = NULL; 811573Srgrimes btopeninfo.prefix = NULL; 821573Srgrimes btopeninfo.lorder = openinfo->lorder; 831573Srgrimes dbp = __bt_open(openinfo->bfname, 841573Srgrimes O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags); 851573Srgrimes } else 861573Srgrimes dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags); 871573Srgrimes if (dbp == NULL) 881573Srgrimes goto err; 891573Srgrimes 901573Srgrimes /* 911573Srgrimes * Some fields in the tree structure are recno specific. Fill them 921573Srgrimes * in and make the btree structure look like a recno structure. We 931573Srgrimes * don't change the bt_ovflsize value, it's close enough and slightly 941573Srgrimes * bigger. 951573Srgrimes */ 961573Srgrimes t = dbp->internal; 971573Srgrimes if (openinfo) { 981573Srgrimes if (openinfo->flags & R_FIXEDLEN) { 9914272Spst F_SET(t, R_FIXLEN); 1001573Srgrimes t->bt_reclen = openinfo->reclen; 1011573Srgrimes if (t->bt_reclen == 0) 1021573Srgrimes goto einval; 1031573Srgrimes } 1041573Srgrimes t->bt_bval = openinfo->bval; 1051573Srgrimes } else 1061573Srgrimes t->bt_bval = '\n'; 1071573Srgrimes 10814272Spst F_SET(t, R_RECNO); 1091573Srgrimes if (fname == NULL) 11014272Spst F_SET(t, R_EOF | R_INMEM); 1111573Srgrimes else 1121573Srgrimes t->bt_rfd = rfd; 1131573Srgrimes 1141573Srgrimes if (fname != NULL) { 1151573Srgrimes /* 1161573Srgrimes * In 4.4BSD, stat(2) returns true for ISSOCK on pipes. 1171573Srgrimes * Unfortunately, that's not portable, so we use lseek 1181573Srgrimes * and check the errno values. 1191573Srgrimes */ 1201573Srgrimes errno = 0; 1211573Srgrimes if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) { 1221573Srgrimes switch (flags & O_ACCMODE) { 1231573Srgrimes case O_RDONLY: 12414272Spst F_SET(t, R_RDONLY); 1251573Srgrimes break; 1261573Srgrimes default: 1271573Srgrimes goto einval; 1281573Srgrimes } 1291573Srgrimesslow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL) 1301573Srgrimes goto err; 13114272Spst F_SET(t, R_CLOSEFP); 1321573Srgrimes t->bt_irec = 13314272Spst F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe; 1341573Srgrimes } else { 1351573Srgrimes switch (flags & O_ACCMODE) { 1361573Srgrimes case O_RDONLY: 13714272Spst F_SET(t, R_RDONLY); 1381573Srgrimes break; 1391573Srgrimes case O_RDWR: 1401573Srgrimes break; 1411573Srgrimes default: 1421573Srgrimes goto einval; 1431573Srgrimes } 1441573Srgrimes 14571579Sdeischen if (_fstat(rfd, &sb)) 1461573Srgrimes goto err; 1471573Srgrimes /* 1481573Srgrimes * Kluge -- we'd like to test to see if the file is too 1491573Srgrimes * big to mmap. Since, we don't know what size or type 1501573Srgrimes * off_t's or size_t's are, what the largest unsigned 1511573Srgrimes * integral type is, or what random insanity the local 1521573Srgrimes * C compiler will perpetrate, doing the comparison in 1531573Srgrimes * a portable way is flatly impossible. Hope that mmap 1541573Srgrimes * fails if the file is too large. 1551573Srgrimes */ 1561573Srgrimes if (sb.st_size == 0) 15714272Spst F_SET(t, R_EOF); 1581573Srgrimes else { 15914272Spst#ifdef MMAP_NOT_AVAILABLE 16014272Spst /* 16114272Spst * XXX 16214272Spst * Mmap doesn't work correctly on many current 16314272Spst * systems. In particular, it can fail subtly, 16414272Spst * with cache coherency problems. Don't use it 16514272Spst * for now. 16614272Spst */ 1671573Srgrimes t->bt_msize = sb.st_size; 1681573Srgrimes if ((t->bt_smap = mmap(NULL, t->bt_msize, 1691573Srgrimes PROT_READ, MAP_PRIVATE, rfd, 17021786Salex (off_t)0)) == MAP_FAILED) 1711573Srgrimes goto slow; 1721573Srgrimes t->bt_cmap = t->bt_smap; 1731573Srgrimes t->bt_emap = t->bt_smap + sb.st_size; 17414272Spst t->bt_irec = F_ISSET(t, R_FIXLEN) ? 1751573Srgrimes __rec_fmap : __rec_vmap; 17614272Spst F_SET(t, R_MEMMAPPED); 17714272Spst#else 17814272Spst goto slow; 17914272Spst#endif 1801573Srgrimes } 1811573Srgrimes } 1821573Srgrimes } 1831573Srgrimes 1841573Srgrimes /* Use the recno routines. */ 1851573Srgrimes dbp->close = __rec_close; 1861573Srgrimes dbp->del = __rec_delete; 1871573Srgrimes dbp->fd = __rec_fd; 1881573Srgrimes dbp->get = __rec_get; 1891573Srgrimes dbp->put = __rec_put; 1901573Srgrimes dbp->seq = __rec_seq; 1911573Srgrimes dbp->sync = __rec_sync; 1921573Srgrimes 1931573Srgrimes /* If the root page was created, reset the flags. */ 1941573Srgrimes if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL) 1951573Srgrimes goto err; 1961573Srgrimes if ((h->flags & P_TYPE) == P_BLEAF) { 19714272Spst F_CLR(h, P_TYPE); 19814272Spst F_SET(h, P_RLEAF); 1991573Srgrimes mpool_put(t->bt_mp, h, MPOOL_DIRTY); 2001573Srgrimes } else 2011573Srgrimes mpool_put(t->bt_mp, h, 0); 2021573Srgrimes 2031573Srgrimes if (openinfo && openinfo->flags & R_SNAPSHOT && 20414272Spst !F_ISSET(t, R_EOF | R_INMEM) && 2051573Srgrimes t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR) 206189327Sdelphij goto err; 2071573Srgrimes return (dbp); 2081573Srgrimes 2091573Srgrimeseinval: errno = EINVAL; 2101573Srgrimeserr: sverrno = errno; 2111573Srgrimes if (dbp != NULL) 2121573Srgrimes (void)__bt_close(dbp); 2131573Srgrimes if (fname != NULL) 21456698Sjasone (void)_close(rfd); 2151573Srgrimes errno = sverrno; 2161573Srgrimes return (NULL); 2171573Srgrimes} 2181573Srgrimes 2191573Srgrimesint 220189291Sdelphij__rec_fd(const DB *dbp) 2211573Srgrimes{ 2221573Srgrimes BTREE *t; 2231573Srgrimes 2241573Srgrimes t = dbp->internal; 2251573Srgrimes 2261573Srgrimes /* Toss any page pinned across calls. */ 2271573Srgrimes if (t->bt_pinned != NULL) { 2281573Srgrimes mpool_put(t->bt_mp, t->bt_pinned, 0); 2291573Srgrimes t->bt_pinned = NULL; 2301573Srgrimes } 2311573Srgrimes 2321573Srgrimes /* In-memory database can't have a file descriptor. */ 23314272Spst if (F_ISSET(t, R_INMEM)) { 2341573Srgrimes errno = ENOENT; 2351573Srgrimes return (-1); 2361573Srgrimes } 2371573Srgrimes return (t->bt_rfd); 2381573Srgrimes} 239