150995Sbostic /*- 261207Sbostic * Copyright (c) 1990, 1993 361207Sbostic * The Regents of the University of California. All rights reserved. 450995Sbostic * 550995Sbostic * This code is derived from software contributed to Berkeley by 650995Sbostic * Mike Olson. 750995Sbostic * 850995Sbostic * %sccs.include.redist.c% 950995Sbostic */ 1050995Sbostic 1150995Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*64462Sbostic static char sccsid[] = "@(#)rec_open.c 8.3 (Berkeley) 09/07/93"; 1350995Sbostic #endif /* LIBC_SCCS and not lint */ 1450995Sbostic 1550995Sbostic #include <sys/types.h> 1650995Sbostic #include <sys/mman.h> 1750995Sbostic #include <sys/stat.h> 1854362Sbostic 1956757Sbostic #include <errno.h> 2050995Sbostic #include <fcntl.h> 2150995Sbostic #include <limits.h> 2256757Sbostic #include <stddef.h> 2356757Sbostic #include <stdio.h> 2450995Sbostic #include <unistd.h> 2556757Sbostic 2657933Sbostic #include <db.h> 2751090Sbostic #include "recno.h" 2850995Sbostic 2950995Sbostic DB * 30*64462Sbostic __rec_open(fname, flags, mode, openinfo, dflags) 3150995Sbostic const char *fname; 32*64462Sbostic int flags, mode, dflags; 3350995Sbostic const RECNOINFO *openinfo; 3450995Sbostic { 3550995Sbostic BTREE *t; 3650995Sbostic BTREEINFO btopeninfo; 3750995Sbostic DB *dbp; 3850995Sbostic PAGE *h; 3950995Sbostic struct stat sb; 4058751Sbostic int rfd, sverrno; 4150995Sbostic 4250995Sbostic /* Open the user's file -- if this fails, we're done. */ 4356757Sbostic if (fname != NULL && (rfd = open(fname, flags, mode)) < 0) 4450995Sbostic return (NULL); 4550995Sbostic 4650995Sbostic /* Create a btree in memory (backed by disk). */ 4756757Sbostic dbp = NULL; 4850995Sbostic if (openinfo) { 4956757Sbostic if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT)) 5056703Sbostic goto einval; 5150995Sbostic btopeninfo.flags = 0; 5250995Sbostic btopeninfo.cachesize = openinfo->cachesize; 5358790Sralph btopeninfo.maxkeypage = 0; 5458790Sralph btopeninfo.minkeypage = 0; 5560065Sbostic btopeninfo.psize = openinfo->psize; 5650995Sbostic btopeninfo.compare = NULL; 5758790Sralph btopeninfo.prefix = NULL; 5850995Sbostic btopeninfo.lorder = openinfo->lorder; 5960055Sbostic dbp = __bt_open(openinfo->bfname, 60*64462Sbostic O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags); 6150995Sbostic } else 62*64462Sbostic dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags); 6351090Sbostic if (dbp == NULL) 6451090Sbostic goto err; 6550995Sbostic 6650995Sbostic /* 6750995Sbostic * Some fields in the tree structure are recno specific. Fill them 6851090Sbostic * in and make the btree structure look like a recno structure. We 6951090Sbostic * don't change the bt_ovflsize value, it's close enough and slightly 7051090Sbostic * bigger. 7150995Sbostic */ 7250995Sbostic t = dbp->internal; 7350995Sbostic if (openinfo) { 7455295Sbostic if (openinfo->flags & R_FIXEDLEN) { 7560055Sbostic SET(t, R_FIXLEN); 7655295Sbostic t->bt_reclen = openinfo->reclen; 7756703Sbostic if (t->bt_reclen == 0) 7856703Sbostic goto einval; 7950995Sbostic } 8050995Sbostic t->bt_bval = openinfo->bval; 8150995Sbostic } else 8250995Sbostic t->bt_bval = '\n'; 8350995Sbostic 8460055Sbostic SET(t, R_RECNO); 8558751Sbostic if (fname == NULL) 8660055Sbostic SET(t, R_EOF | R_INMEM); 8758751Sbostic else 8858751Sbostic t->bt_rfd = rfd; 8957007Sbostic t->bt_rcursor = 0; 9050995Sbostic 9150995Sbostic /* 9254286Sbostic * In 4.4BSD stat(2) returns true for ISSOCK on pipes. Until 9354286Sbostic * then, this is fairly close. Pipes are read-only. 9454286Sbostic */ 9558790Sralph if (fname != NULL) { 9656757Sbostic if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) { 9758790Sralph switch (flags & O_ACCMODE) { 9858751Sbostic case O_RDONLY: 9960055Sbostic SET(t, R_RDONLY); 10058751Sbostic break; 10158751Sbostic default: 10258751Sbostic goto einval; 10358751Sbostic } 10457227Sbostic slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL) 10556757Sbostic goto err; 10660055Sbostic SET(t, R_CLOSEFP); 10756757Sbostic t->bt_irec = 10860055Sbostic ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe; 10956757Sbostic } else { 11058790Sralph switch (flags & O_ACCMODE) { 11156757Sbostic case O_RDONLY: 11260055Sbostic SET(t, R_RDONLY); 11356757Sbostic break; 11456757Sbostic case O_RDWR: 11556757Sbostic break; 11656757Sbostic default: 11756757Sbostic goto einval; 11856757Sbostic } 11958790Sralph 12058751Sbostic if (fstat(rfd, &sb)) 12158751Sbostic goto err; 12259772Sbostic /* 12360613Sbostic * Kluge -- we'd like to test to see if the file is too 12460613Sbostic * big to mmap. Since, we don't know what size or type 12560613Sbostic * off_t's or size_t's are, what the largest unsigned 12660613Sbostic * integral type is, or what random insanity the local 12760613Sbostic * C compiler will perpetrate, doing the comparison in 12860613Sbostic * a portable way is flatly impossible. Hope that mmap 12960613Sbostic * fails if the file is too large. 13059772Sbostic */ 13158751Sbostic if (sb.st_size == 0) 13260055Sbostic SET(t, R_EOF); 13358751Sbostic else { 13458751Sbostic t->bt_msize = sb.st_size; 13564280Sbostic if ((t->bt_smap = mmap(NULL, t->bt_msize, 13664280Sbostic PROT_READ, MAP_PRIVATE, rfd, 13758751Sbostic (off_t)0)) == (caddr_t)-1) 13858751Sbostic goto slow; 13958751Sbostic t->bt_cmap = t->bt_smap; 14058751Sbostic t->bt_emap = t->bt_smap + sb.st_size; 14160055Sbostic t->bt_irec = ISSET(t, R_FIXLEN) ? 14258751Sbostic __rec_fmap : __rec_vmap; 14360055Sbostic SET(t, R_MEMMAPPED); 14458751Sbostic } 14556703Sbostic } 14658790Sralph } 14750995Sbostic 14850995Sbostic /* Use the recno routines. */ 14950995Sbostic dbp->close = __rec_close; 15050995Sbostic dbp->del = __rec_delete; 15160269Sbostic dbp->fd = __rec_fd; 15250995Sbostic dbp->get = __rec_get; 15350995Sbostic dbp->put = __rec_put; 15450995Sbostic dbp->seq = __rec_seq; 15550995Sbostic dbp->sync = __rec_sync; 15650995Sbostic 15750995Sbostic /* If the root page was created, reset the flags. */ 15850995Sbostic if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL) 15950995Sbostic goto err; 16050995Sbostic if ((h->flags & P_TYPE) == P_BLEAF) { 16150995Sbostic h->flags = h->flags & ~P_TYPE | P_RLEAF; 16250995Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 16350995Sbostic } else 16450995Sbostic mpool_put(t->bt_mp, h, 0); 16550995Sbostic 16650995Sbostic if (openinfo && openinfo->flags & R_SNAPSHOT && 16760055Sbostic !ISSET(t, R_EOF | R_INMEM) && 16850995Sbostic t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR) 16950995Sbostic goto err; 17050995Sbostic return (dbp); 17150995Sbostic 17256703Sbostic einval: errno = EINVAL; 17358751Sbostic err: sverrno = errno; 17458751Sbostic if (dbp != NULL) 17558751Sbostic (void)__bt_close(dbp); 17656757Sbostic if (fname != NULL) 17756757Sbostic (void)close(rfd); 17858751Sbostic errno = sverrno; 17950995Sbostic return (NULL); 18050995Sbostic } 18160269Sbostic 18260269Sbostic int 18360269Sbostic __rec_fd(dbp) 18460269Sbostic const DB *dbp; 18560269Sbostic { 18660269Sbostic BTREE *t; 18760269Sbostic 18860269Sbostic t = dbp->internal; 18960269Sbostic 190*64462Sbostic /* Toss any page pinned across calls. */ 191*64462Sbostic if (t->bt_pinned != NULL) { 192*64462Sbostic mpool_put(t->bt_mp, t->bt_pinned, 0); 193*64462Sbostic t->bt_pinned = NULL; 194*64462Sbostic } 195*64462Sbostic 196*64462Sbostic /* In-memory database can't have a file descriptor. */ 19760269Sbostic if (ISSET(t, R_INMEM)) { 19860269Sbostic errno = ENOENT; 19960269Sbostic return (-1); 20060269Sbostic } 20160269Sbostic return (t->bt_rfd); 20260269Sbostic } 203