1 /*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Mike Olson. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)rec_open.c 8.4 (Berkeley) 09/07/93"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <sys/types.h> 16 #include <sys/mman.h> 17 #include <sys/stat.h> 18 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <limits.h> 22 #include <stddef.h> 23 #include <stdio.h> 24 #include <unistd.h> 25 26 #define __DBINTERFACE_PRIVATE 27 #include <db.h> 28 #include "recno.h" 29 30 DB * 31 __rec_open(fname, flags, mode, openinfo, dflags) 32 const char *fname; 33 int flags, mode, dflags; 34 const RECNOINFO *openinfo; 35 { 36 BTREE *t; 37 BTREEINFO btopeninfo; 38 DB *dbp; 39 PAGE *h; 40 struct stat sb; 41 int rfd, sverrno; 42 43 /* Open the user's file -- if this fails, we're done. */ 44 if (fname != NULL && (rfd = open(fname, flags, mode)) < 0) 45 return (NULL); 46 47 /* Create a btree in memory (backed by disk). */ 48 dbp = NULL; 49 if (openinfo) { 50 if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT)) 51 goto einval; 52 btopeninfo.flags = 0; 53 btopeninfo.cachesize = openinfo->cachesize; 54 btopeninfo.maxkeypage = 0; 55 btopeninfo.minkeypage = 0; 56 btopeninfo.psize = openinfo->psize; 57 btopeninfo.compare = NULL; 58 btopeninfo.prefix = NULL; 59 btopeninfo.lorder = openinfo->lorder; 60 dbp = __bt_open(openinfo->bfname, 61 O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags); 62 } else 63 dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags); 64 if (dbp == NULL) 65 goto err; 66 67 /* 68 * Some fields in the tree structure are recno specific. Fill them 69 * in and make the btree structure look like a recno structure. We 70 * don't change the bt_ovflsize value, it's close enough and slightly 71 * bigger. 72 */ 73 t = dbp->internal; 74 if (openinfo) { 75 if (openinfo->flags & R_FIXEDLEN) { 76 SET(t, R_FIXLEN); 77 t->bt_reclen = openinfo->reclen; 78 if (t->bt_reclen == 0) 79 goto einval; 80 } 81 t->bt_bval = openinfo->bval; 82 } else 83 t->bt_bval = '\n'; 84 85 SET(t, R_RECNO); 86 if (fname == NULL) 87 SET(t, R_EOF | R_INMEM); 88 else 89 t->bt_rfd = rfd; 90 t->bt_rcursor = 0; 91 92 /* 93 * In 4.4BSD stat(2) returns true for ISSOCK on pipes. Until 94 * then, this is fairly close. Pipes are read-only. 95 */ 96 if (fname != NULL) { 97 if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) { 98 switch (flags & O_ACCMODE) { 99 case O_RDONLY: 100 SET(t, R_RDONLY); 101 break; 102 default: 103 goto einval; 104 } 105 slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL) 106 goto err; 107 SET(t, R_CLOSEFP); 108 t->bt_irec = 109 ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe; 110 } else { 111 switch (flags & O_ACCMODE) { 112 case O_RDONLY: 113 SET(t, R_RDONLY); 114 break; 115 case O_RDWR: 116 break; 117 default: 118 goto einval; 119 } 120 121 if (fstat(rfd, &sb)) 122 goto err; 123 /* 124 * Kluge -- we'd like to test to see if the file is too 125 * big to mmap. Since, we don't know what size or type 126 * off_t's or size_t's are, what the largest unsigned 127 * integral type is, or what random insanity the local 128 * C compiler will perpetrate, doing the comparison in 129 * a portable way is flatly impossible. Hope that mmap 130 * fails if the file is too large. 131 */ 132 if (sb.st_size == 0) 133 SET(t, R_EOF); 134 else { 135 t->bt_msize = sb.st_size; 136 if ((t->bt_smap = mmap(NULL, t->bt_msize, 137 PROT_READ, MAP_PRIVATE, rfd, 138 (off_t)0)) == (caddr_t)-1) 139 goto slow; 140 t->bt_cmap = t->bt_smap; 141 t->bt_emap = t->bt_smap + sb.st_size; 142 t->bt_irec = ISSET(t, R_FIXLEN) ? 143 __rec_fmap : __rec_vmap; 144 SET(t, R_MEMMAPPED); 145 } 146 } 147 } 148 149 /* Use the recno routines. */ 150 dbp->close = __rec_close; 151 dbp->del = __rec_delete; 152 dbp->fd = __rec_fd; 153 dbp->get = __rec_get; 154 dbp->put = __rec_put; 155 dbp->seq = __rec_seq; 156 dbp->sync = __rec_sync; 157 158 /* If the root page was created, reset the flags. */ 159 if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL) 160 goto err; 161 if ((h->flags & P_TYPE) == P_BLEAF) { 162 h->flags = h->flags & ~P_TYPE | P_RLEAF; 163 mpool_put(t->bt_mp, h, MPOOL_DIRTY); 164 } else 165 mpool_put(t->bt_mp, h, 0); 166 167 if (openinfo && openinfo->flags & R_SNAPSHOT && 168 !ISSET(t, R_EOF | R_INMEM) && 169 t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR) 170 goto err; 171 return (dbp); 172 173 einval: errno = EINVAL; 174 err: sverrno = errno; 175 if (dbp != NULL) 176 (void)__bt_close(dbp); 177 if (fname != NULL) 178 (void)close(rfd); 179 errno = sverrno; 180 return (NULL); 181 } 182 183 int 184 __rec_fd(dbp) 185 const DB *dbp; 186 { 187 BTREE *t; 188 189 t = dbp->internal; 190 191 /* Toss any page pinned across calls. */ 192 if (t->bt_pinned != NULL) { 193 mpool_put(t->bt_mp, t->bt_pinned, 0); 194 t->bt_pinned = NULL; 195 } 196 197 /* In-memory database can't have a file descriptor. */ 198 if (ISSET(t, R_INMEM)) { 199 errno = ENOENT; 200 return (-1); 201 } 202 return (t->bt_rfd); 203 } 204