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