]> git.saurik.com Git - apple/libc.git/blob - db.subproj/recno.subproj/rec_open.c
4f8743e51a30d5d57eaf6267fd3a657602813d55
[apple/libc.git] / db.subproj / recno.subproj / rec_open.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1990, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * This code is derived from software contributed to Berkeley by
27 * Mike Olson.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58
59 #include <sys/types.h>
60 #include <sys/stat.h>
61
62 #include <mach/mach.h>
63 #include <mach/mach_traps.h>
64
65 #include <errno.h>
66 #include <fcntl.h>
67 #include <limits.h>
68 #include <stddef.h>
69 #include <stdio.h>
70 #include <unistd.h>
71
72 #include <db.h>
73 #include "recno.h"
74
75 DB *
76 __rec_open(fname, flags, mode, openinfo, dflags)
77 const char *fname;
78 int flags, mode, dflags;
79 const RECNOINFO *openinfo;
80 {
81 BTREE *t;
82 BTREEINFO btopeninfo;
83 DB *dbp;
84 PAGE *h;
85 struct stat sb;
86 int rfd, sverrno;
87
88 /* Open the user's file -- if this fails, we're done. */
89 if (fname != NULL && (rfd = open(fname, flags, mode)) < 0)
90 return (NULL);
91
92 /* Create a btree in memory (backed by disk). */
93 dbp = NULL;
94 if (openinfo) {
95 if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
96 goto einval;
97 btopeninfo.flags = 0;
98 btopeninfo.cachesize = openinfo->cachesize;
99 btopeninfo.maxkeypage = 0;
100 btopeninfo.minkeypage = 0;
101 btopeninfo.psize = openinfo->psize;
102 btopeninfo.compare = NULL;
103 btopeninfo.prefix = NULL;
104 btopeninfo.lorder = openinfo->lorder;
105 dbp = __bt_open(openinfo->bfname,
106 O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
107 } else
108 dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags);
109 if (dbp == NULL)
110 goto err;
111
112 /*
113 * Some fields in the tree structure are recno specific. Fill them
114 * in and make the btree structure look like a recno structure. We
115 * don't change the bt_ovflsize value, it's close enough and slightly
116 * bigger.
117 */
118 t = dbp->internal;
119 if (openinfo) {
120 if (openinfo->flags & R_FIXEDLEN) {
121 SET(t, R_FIXLEN);
122 t->bt_reclen = openinfo->reclen;
123 if (t->bt_reclen == 0)
124 goto einval;
125 }
126 t->bt_bval = openinfo->bval;
127 } else
128 t->bt_bval = '\n';
129
130 SET(t, R_RECNO);
131 if (fname == NULL)
132 SET(t, R_EOF | R_INMEM);
133 else
134 t->bt_rfd = rfd;
135 t->bt_rcursor = 0;
136
137 if (fname != NULL) {
138 /*
139 * In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
140 * Unfortunately, that's not portable, so we use lseek
141 * and check the errno values.
142 */
143 errno = 0;
144 if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
145 switch (flags & O_ACCMODE) {
146 case O_RDONLY:
147 SET(t, R_RDONLY);
148 break;
149 default:
150 goto einval;
151 }
152 slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
153 goto err;
154 SET(t, R_CLOSEFP);
155 t->bt_irec =
156 ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
157 } else {
158 switch (flags & O_ACCMODE) {
159 case O_RDONLY:
160 SET(t, R_RDONLY);
161 break;
162 case O_RDWR:
163 break;
164 default:
165 goto einval;
166 }
167
168 if (fstat(rfd, &sb))
169 goto err;
170 /*
171 * Kluge -- we'd like to test to see if the file is too
172 * big to mmap. Since, we don't know what size or type
173 * off_t's or size_t's are, what the largest unsigned
174 * integral type is, or what random insanity the local
175 * C compiler will perpetrate, doing the comparison in
176 * a portable way is flatly impossible. Hope that mmap
177 * fails if the file is too large.
178 */
179 if (sb.st_size == 0)
180 SET(t, R_EOF);
181 else {
182 t->bt_msize = sb.st_size;
183 if ( (map_fd(rfd, 0, (vm_offset_t *)
184 &t->bt_smap, TRUE, t->bt_msize)
185 != KERN_SUCCESS)
186 || (vm_protect(mach_task_self(), (vm_offset_t)
187 t->bt_smap, t->bt_msize, TRUE,
188 VM_PROT_READ) != KERN_SUCCESS) )
189 goto slow;
190 t->bt_cmap = t->bt_smap;
191 t->bt_emap = t->bt_smap + sb.st_size;
192 t->bt_irec = ISSET(t, R_FIXLEN) ?
193 __rec_fmap : __rec_vmap;
194 SET(t, R_MEMMAPPED);
195 }
196 }
197 }
198
199 /* Use the recno routines. */
200 dbp->close = __rec_close;
201 dbp->del = __rec_delete;
202 dbp->fd = __rec_fd;
203 dbp->get = __rec_get;
204 dbp->put = __rec_put;
205 dbp->seq = __rec_seq;
206 dbp->sync = __rec_sync;
207
208 /* If the root page was created, reset the flags. */
209 if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
210 goto err;
211 if ((h->flags & P_TYPE) == P_BLEAF) {
212 h->flags = h->flags & ~P_TYPE | P_RLEAF;
213 mpool_put(t->bt_mp, h, MPOOL_DIRTY);
214 } else
215 mpool_put(t->bt_mp, h, 0);
216
217 if (openinfo && openinfo->flags & R_SNAPSHOT &&
218 !ISSET(t, R_EOF | R_INMEM) &&
219 t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
220 goto err;
221 return (dbp);
222
223 einval: errno = EINVAL;
224 err: sverrno = errno;
225 if (dbp != NULL)
226 (void)__bt_close(dbp);
227 if (fname != NULL)
228 (void)close(rfd);
229 errno = sverrno;
230 return (NULL);
231 }
232
233 int
234 __rec_fd(dbp)
235 const DB *dbp;
236 {
237 BTREE *t;
238
239 t = dbp->internal;
240
241 /* Toss any page pinned across calls. */
242 if (t->bt_pinned != NULL) {
243 mpool_put(t->bt_mp, t->bt_pinned, 0);
244 t->bt_pinned = NULL;
245 }
246
247 /* In-memory database can't have a file descriptor. */
248 if (ISSET(t, R_INMEM)) {
249 errno = ENOENT;
250 return (-1);
251 }
252 return (t->bt_rfd);
253 }