/*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Mike Olson. * * %sccs.include.redist.c% */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)rec_open.c 5.18 (Berkeley) 05/16/93"; #endif /* LIBC_SCCS and not lint */ #include #include #include #include #include #include #include #include #include #include #include "recno.h" DB * __rec_open(fname, flags, mode, openinfo) const char *fname; int flags, mode; const RECNOINFO *openinfo; { BTREE *t; BTREEINFO btopeninfo; DB *dbp; PAGE *h; struct stat sb; int rfd, sverrno; /* Open the user's file -- if this fails, we're done. */ if (fname != NULL && (rfd = open(fname, flags, mode)) < 0) return (NULL); /* Create a btree in memory (backed by disk). */ dbp = NULL; if (openinfo) { if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT)) goto einval; btopeninfo.flags = 0; btopeninfo.cachesize = openinfo->cachesize; btopeninfo.maxkeypage = 0; btopeninfo.minkeypage = 0; btopeninfo.psize = 0; btopeninfo.compare = NULL; btopeninfo.prefix = NULL; btopeninfo.lorder = openinfo->lorder; dbp = __bt_open(openinfo->bfname, O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo); } else dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL); if (dbp == NULL) goto err; /* * Some fields in the tree structure are recno specific. Fill them * in and make the btree structure look like a recno structure. We * don't change the bt_ovflsize value, it's close enough and slightly * bigger. */ t = dbp->internal; if (openinfo) { if (openinfo->flags & R_FIXEDLEN) { SET(t, R_FIXLEN); t->bt_reclen = openinfo->reclen; if (t->bt_reclen == 0) goto einval; } t->bt_bval = openinfo->bval; } else t->bt_bval = '\n'; SET(t, R_RECNO); if (fname == NULL) SET(t, R_EOF | R_INMEM); else t->bt_rfd = rfd; t->bt_rcursor = 0; /* * In 4.4BSD stat(2) returns true for ISSOCK on pipes. Until * then, this is fairly close. Pipes are read-only. */ if (fname != NULL) { if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) { switch (flags & O_ACCMODE) { case O_RDONLY: SET(t, R_RDONLY); break; default: goto einval; } slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL) goto err; SET(t, R_CLOSEFP); t->bt_irec = ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe; } else { switch (flags & O_ACCMODE) { case O_RDONLY: SET(t, R_RDONLY); break; case O_RDWR: break; default: goto einval; } if (fstat(rfd, &sb)) goto err; /* * Kludge -- but we don't know what size an off_t * is or what size a size_t is, although we do * know that the former is signed and the latter * unsigned. */ if (sizeof(sb.st_size) > sizeof(size_t)) { if (sb.st_size > (off_t)SIZE_T_MAX) { errno = EFBIG; goto err; } } else { if ((size_t)sb.st_size > SIZE_T_MAX) { errno = EFBIG; goto err; } } if (sb.st_size == 0) SET(t, R_EOF); else { t->bt_msize = sb.st_size; if ((t->bt_smap = mmap(NULL, t->bt_msize, PROT_READ, 0, rfd, (off_t)0)) == (caddr_t)-1) goto slow; t->bt_cmap = t->bt_smap; t->bt_emap = t->bt_smap + sb.st_size; t->bt_irec = ISSET(t, R_FIXLEN) ? __rec_fmap : __rec_vmap; SET(t, R_MEMMAPPED); } } } /* Use the recno routines. */ dbp->close = __rec_close; dbp->del = __rec_delete; dbp->get = __rec_get; dbp->put = __rec_put; dbp->seq = __rec_seq; dbp->sync = __rec_sync; /* If the root page was created, reset the flags. */ if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL) goto err; if ((h->flags & P_TYPE) == P_BLEAF) { h->flags = h->flags & ~P_TYPE | P_RLEAF; mpool_put(t->bt_mp, h, MPOOL_DIRTY); } else mpool_put(t->bt_mp, h, 0); if (openinfo && openinfo->flags & R_SNAPSHOT && !ISSET(t, R_EOF | R_INMEM) && t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR) goto err; return (dbp); einval: errno = EINVAL; err: sverrno = errno; if (dbp != NULL) (void)__bt_close(dbp); if (fname != NULL) (void)close(rfd); errno = sverrno; return (NULL); }