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*66228Sbostic static char sccsid[] = "@(#)rec_open.c 8.6 (Berkeley) 02/22/94";
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 *
__rec_open(fname,flags,mode,openinfo,dflags)3064462Sbostic __rec_open(fname, flags, mode, openinfo, dflags)
3150995Sbostic const char *fname;
3264462Sbostic 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,
6064462Sbostic O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
6150995Sbostic } else
6264462Sbostic 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
9158790Sralph if (fname != NULL) {
92*66228Sbostic /*
93*66228Sbostic * In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
94*66228Sbostic * Unfortunately, that's not portable, so we use lseek
95*66228Sbostic * and check the errno values.
96*66228Sbostic */
97*66228Sbostic errno = 0;
9856757Sbostic if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
9958790Sralph switch (flags & O_ACCMODE) {
10058751Sbostic case O_RDONLY:
10160055Sbostic SET(t, R_RDONLY);
10258751Sbostic break;
10358751Sbostic default:
10458751Sbostic goto einval;
10558751Sbostic }
10657227Sbostic slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
10756757Sbostic goto err;
10860055Sbostic SET(t, R_CLOSEFP);
10956757Sbostic t->bt_irec =
11060055Sbostic ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
11156757Sbostic } else {
11258790Sralph switch (flags & O_ACCMODE) {
11356757Sbostic case O_RDONLY:
11460055Sbostic SET(t, R_RDONLY);
11556757Sbostic break;
11656757Sbostic case O_RDWR:
11756757Sbostic break;
11856757Sbostic default:
11956757Sbostic goto einval;
12056757Sbostic }
12158790Sralph
12258751Sbostic if (fstat(rfd, &sb))
12358751Sbostic goto err;
12459772Sbostic /*
12560613Sbostic * Kluge -- we'd like to test to see if the file is too
12660613Sbostic * big to mmap. Since, we don't know what size or type
12760613Sbostic * off_t's or size_t's are, what the largest unsigned
12860613Sbostic * integral type is, or what random insanity the local
12960613Sbostic * C compiler will perpetrate, doing the comparison in
13060613Sbostic * a portable way is flatly impossible. Hope that mmap
13160613Sbostic * fails if the file is too large.
13259772Sbostic */
13358751Sbostic if (sb.st_size == 0)
13460055Sbostic SET(t, R_EOF);
13558751Sbostic else {
13658751Sbostic t->bt_msize = sb.st_size;
13764280Sbostic if ((t->bt_smap = mmap(NULL, t->bt_msize,
13864280Sbostic PROT_READ, MAP_PRIVATE, rfd,
13958751Sbostic (off_t)0)) == (caddr_t)-1)
14058751Sbostic goto slow;
14158751Sbostic t->bt_cmap = t->bt_smap;
14258751Sbostic t->bt_emap = t->bt_smap + sb.st_size;
14360055Sbostic t->bt_irec = ISSET(t, R_FIXLEN) ?
14458751Sbostic __rec_fmap : __rec_vmap;
14560055Sbostic SET(t, R_MEMMAPPED);
14658751Sbostic }
14756703Sbostic }
14858790Sralph }
14950995Sbostic
15050995Sbostic /* Use the recno routines. */
15150995Sbostic dbp->close = __rec_close;
15250995Sbostic dbp->del = __rec_delete;
15360269Sbostic dbp->fd = __rec_fd;
15450995Sbostic dbp->get = __rec_get;
15550995Sbostic dbp->put = __rec_put;
15650995Sbostic dbp->seq = __rec_seq;
15750995Sbostic dbp->sync = __rec_sync;
15850995Sbostic
15950995Sbostic /* If the root page was created, reset the flags. */
16050995Sbostic if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
16150995Sbostic goto err;
16250995Sbostic if ((h->flags & P_TYPE) == P_BLEAF) {
16350995Sbostic h->flags = h->flags & ~P_TYPE | P_RLEAF;
16450995Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY);
16550995Sbostic } else
16650995Sbostic mpool_put(t->bt_mp, h, 0);
16750995Sbostic
16850995Sbostic if (openinfo && openinfo->flags & R_SNAPSHOT &&
16960055Sbostic !ISSET(t, R_EOF | R_INMEM) &&
17050995Sbostic t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
17150995Sbostic goto err;
17250995Sbostic return (dbp);
17350995Sbostic
17456703Sbostic einval: errno = EINVAL;
17558751Sbostic err: sverrno = errno;
17658751Sbostic if (dbp != NULL)
17758751Sbostic (void)__bt_close(dbp);
17856757Sbostic if (fname != NULL)
17956757Sbostic (void)close(rfd);
18058751Sbostic errno = sverrno;
18150995Sbostic return (NULL);
18250995Sbostic }
18360269Sbostic
18460269Sbostic int
__rec_fd(dbp)18560269Sbostic __rec_fd(dbp)
18660269Sbostic const DB *dbp;
18760269Sbostic {
18860269Sbostic BTREE *t;
18960269Sbostic
19060269Sbostic t = dbp->internal;
19160269Sbostic
19264462Sbostic /* Toss any page pinned across calls. */
19364462Sbostic if (t->bt_pinned != NULL) {
19464462Sbostic mpool_put(t->bt_mp, t->bt_pinned, 0);
19564462Sbostic t->bt_pinned = NULL;
19664462Sbostic }
19764462Sbostic
19864462Sbostic /* In-memory database can't have a file descriptor. */
19960269Sbostic if (ISSET(t, R_INMEM)) {
20060269Sbostic errno = ENOENT;
20160269Sbostic return (-1);
20260269Sbostic }
20360269Sbostic return (t->bt_rfd);
20460269Sbostic }
205