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