source: main/tags/2.20/gsdl/packages/wingdbm/gdbmopen.c@ 21411

Last change on this file since 21411 was 525, checked in by rjmcnab, 25 years ago

added need_filelock option to open

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
Line 
1/* gdbmopen.c - Open the dbm file and initialize data structures for use. */
2
3/* This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
4 Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc.
5
6 GDBM is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GDBM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GDBM; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 You may contact the author by:
21 e-mail: [email protected]
22 us-mail: Philip A. Nelson
23 Computer Science Department
24 Western Washington University
25 Bellingham, WA 98226
26
27*************************************************************************/
28
29
30/* AIX demands this be the very first thing in the file. */
31#if !defined(__GNUC__) && defined(_AIX)
32 #pragma alloca
33#endif
34
35/* include system configuration before all else. */
36#include "autoconf.h"
37
38#include "gdbmdefs.h"
39#include "gdbmerrno.h"
40
41/* Initialize dbm system. FILE is a pointer to the file name. If the file
42 has a size of zero bytes, a file initialization procedure is performed,
43 setting up the initial structure in the file. BLOCK_SIZE is used during
44 initialization to determine the size of various constructs. If the value
45 is less than 512, the file system blocksize is used, otherwise the value
46 of BLOCK_SIZE is used. BLOCK_SIZE is ignored if the file has previously
47 initialized. If FLAGS is set to GDBM_READ the user wants to just
48 read the database and any call to dbm_store or dbm_delete will fail. Many
49 readers can access the database at the same time. If FLAGS is set to
50 GDBM_WRITE, the user wants both read and write access to the database and
51 requires exclusive access. If FLAGS is GDBM_WRCREAT, the user wants
52 both read and write access to the database and if the database does not
53 exist, create a new one. If FLAGS is GDBM_NEWDB, the user want a
54 new database created, regardless of whether one existed, and wants read
55 and write access to the new database. Any error detected will cause a
56 return value of null and an approprate value will be in gdbm_errno. If
57 no errors occur, a pointer to the "gdbm file descriptor" will be
58 returned. */
59
60
61gdbm_file_info *
62gdbm_open (file, block_size, flags, mode, fatal_func, need_filelock)
63 char *file;
64 int block_size;
65 int flags;
66 int mode;
67 void (*fatal_func) ();
68 int need_filelock;
69{
70 gdbm_file_info *dbf; /* The record to return. */
71 struct stat file_stat; /* Space for the stat information. */
72 int len; /* Length of the file name. */
73 int num_bytes; /* Used in reading and writing. */
74 off_t file_pos; /* Used with seeks. */
75 int lock_val; /* Returned by the flock call. */
76 int file_block_size; /* Block size to use for a new file. */
77 int index; /* Used as a loop index. */
78 char need_trunc; /* Used with GDBM_NEWDB and locking to avoid
79 truncating a file from under a reader. */
80
81 /* Initialize the gdbm_errno variable. */
82 gdbm_errno = GDBM_NO_ERROR;
83
84 /* Allocate new info structure. */
85 dbf = (gdbm_file_info *) malloc (sizeof (gdbm_file_info));
86 if (dbf == NULL)
87 {
88 gdbm_errno = GDBM_MALLOC_ERROR;
89 return NULL;
90 }
91
92 /* Initialize some fields for known values. This is done so gdbm_close
93 will work if called before allocating some structures. */
94 dbf->need_filelock = need_filelock;
95 dbf->dir = NULL;
96 dbf->bucket = NULL;
97 dbf->header = NULL;
98 dbf->bucket_cache = NULL;
99 dbf->cache_size = 0;
100
101 /* Save name of file. */
102 len = strlen (file);
103 dbf->name = (char *) malloc (len + 1);
104 if (dbf->name == NULL)
105 {
106 free (dbf);
107 gdbm_errno = GDBM_MALLOC_ERROR;
108 return NULL;
109 }
110 strcpy (dbf->name, file);
111
112 /* Initialize the fatal error routine. */
113 dbf->fatal_err = fatal_func;
114
115 /* Check for fast writers. */
116 if (flags & GDBM_FAST)
117 {
118 dbf->fast_write = TRUE;
119 flags -= GDBM_FAST;
120 }
121 else
122 {
123 dbf->fast_write = FALSE;
124 }
125
126 /* Open the file. */
127 need_trunc = FALSE;
128 if (flags == GDBM_READER)
129 {
130 dbf->desc = open (dbf->name, O_RDONLY|O_BINARY, 0);
131 }
132 else if (flags == GDBM_WRITER)
133 {
134 dbf->desc = open (dbf->name, O_RDWR|O_BINARY, 0);
135 }
136 else if (flags == GDBM_NEWDB)
137 {
138 dbf->desc = open (dbf->name, O_RDWR|O_CREAT|O_BINARY, mode);
139 flags = GDBM_WRITER;
140 need_trunc = TRUE;
141 }
142 else
143 {
144 dbf->desc = open (dbf->name, O_RDWR|O_CREAT|O_BINARY, mode);
145 flags = GDBM_WRITER;
146 }
147 if (dbf->desc < 0)
148 {
149 free (dbf->name);
150 free (dbf);
151 gdbm_errno = GDBM_FILE_OPEN_ERROR;
152 return NULL;
153 }
154
155 /* Get the status of the file. */
156 fstat (dbf->desc, &file_stat);
157
158 /* Lock the file in the approprate way. */
159 if (flags == GDBM_READER)
160 {
161 if (file_stat.st_size == 0)
162 {
163 close (dbf->desc);
164 free (dbf->name);
165 free (dbf);
166 gdbm_errno = GDBM_EMPTY_DATABASE;
167 return NULL;
168 }
169 /* Sets lock_val to 0 for success. See systems.h. */
170 if (dbf->need_filelock) {
171 READLOCK_FILE(dbf);
172 } else {
173 lock_val = 0;
174 }
175 }
176 else
177 {
178 /* Sets lock_val to 0 for success. See systems.h. */
179 if (dbf->need_filelock) {
180 WRITELOCK_FILE(dbf);
181 } else {
182 lock_val = 0;
183 }
184 }
185 if (lock_val != 0)
186 {
187 close (dbf->desc);
188 free (dbf->name);
189 free (dbf);
190 if (flags == GDBM_READER)
191 gdbm_errno = GDBM_CANT_BE_READER;
192 else
193 gdbm_errno = GDBM_CANT_BE_WRITER;
194 return NULL;
195 }
196
197 /* Record the kind of user. */
198 dbf->read_write = flags;
199
200 /* If we do have a write lock and it was a GDBM_NEWDB, it is
201 now time to truncate the file. */
202 if (need_trunc && file_stat.st_size != 0)
203 {
204 TRUNCATE (dbf);
205 fstat (dbf->desc, &file_stat);
206 }
207
208 /* Decide if this is a new file or an old file. */
209 if (file_stat.st_size == 0)
210 {
211
212 /* This is a new file. Create an empty database. */
213
214 /* Start with the blocksize. */
215 if (block_size < 512)
216 file_block_size = STATBLKSIZE;
217 else
218 file_block_size = block_size;
219
220 /* Get space for the file header. */
221 dbf->header = (gdbm_file_header *) malloc (file_block_size);
222 if (dbf->header == NULL)
223 {
224 gdbm_close (dbf);
225 gdbm_errno = GDBM_MALLOC_ERROR;
226 return NULL;
227 }
228
229 /* Set the magic number and the block_size. */
230 dbf->header->header_magic = 0x13579ace;
231 dbf->header->block_size = file_block_size;
232
233 /* Create the initial hash table directory. */
234 dbf->header->dir_size = 8 * sizeof (off_t);
235 dbf->header->dir_bits = 3;
236 while (dbf->header->dir_size < dbf->header->block_size)
237 {
238 dbf->header->dir_size <<= 1;
239 dbf->header->dir_bits += 1;
240 }
241
242 /* Check for correct block_size. */
243 if (dbf->header->dir_size != dbf->header->block_size)
244 {
245 gdbm_close (dbf);
246 gdbm_errno = GDBM_BLOCK_SIZE_ERROR;
247 return NULL;
248 }
249
250 /* Allocate the space for the directory. */
251 dbf->dir = (off_t *) malloc (dbf->header->dir_size);
252 if (dbf->dir == NULL)
253 {
254 gdbm_close (dbf);
255 gdbm_errno = GDBM_MALLOC_ERROR;
256 return NULL;
257 }
258 dbf->header->dir = dbf->header->block_size;
259
260 /* Create the first and only hash bucket. */
261 dbf->header->bucket_elems =
262 (dbf->header->block_size - sizeof (hash_bucket))
263 / sizeof (bucket_element) + 1;
264 dbf->header->bucket_size = dbf->header->block_size;
265#if !defined(sgi)
266 dbf->bucket = (hash_bucket *) (alloca (dbf->header->bucket_size));
267#else /* sgi */
268 /* The SGI C compiler doesn't accept the previous form. */
269 {
270 hash_bucket *ptr;
271 ptr = (hash_bucket *) (alloca (dbf->header->bucket_size));
272 dbf->bucket = ptr;
273 }
274#endif /* sgi */
275 if (dbf->bucket == NULL)
276 {
277 gdbm_close (dbf);
278 gdbm_errno = GDBM_MALLOC_ERROR;
279 return NULL;
280 }
281 _gdbm_new_bucket (dbf, dbf->bucket, 0);
282 dbf->bucket->av_count = 1;
283 dbf->bucket->bucket_avail[0].av_adr = 3*dbf->header->block_size;
284 dbf->bucket->bucket_avail[0].av_size = dbf->header->block_size;
285
286 /* Set table entries to point to hash buckets. */
287 for (index = 0; index < dbf->header->dir_size / sizeof (off_t); index++)
288 dbf->dir[index] = 2*dbf->header->block_size;
289
290 /* Initialize the active avail block. */
291 dbf->header->avail.size
292 = ( (dbf->header->block_size - sizeof (gdbm_file_header))
293 / sizeof (avail_elem)) + 1;
294 dbf->header->avail.count = 0;
295 dbf->header->avail.next_block = 0;
296 dbf->header->next_block = 4*dbf->header->block_size;
297
298 /* Write initial configuration to the file. */
299 /* Block 0 is the file header and active avail block. */
300 num_bytes = write (dbf->desc, dbf->header, dbf->header->block_size);
301 if (num_bytes != dbf->header->block_size)
302 {
303 gdbm_close (dbf);
304 gdbm_errno = GDBM_FILE_WRITE_ERROR;
305 return NULL;
306 }
307
308 /* Block 1 is the initial bucket directory. */
309 num_bytes = write (dbf->desc, dbf->dir, dbf->header->dir_size);
310 if (num_bytes != dbf->header->dir_size)
311 {
312 gdbm_close (dbf);
313 gdbm_errno = GDBM_FILE_WRITE_ERROR;
314 return NULL;
315 }
316
317 /* Block 2 is the only bucket. */
318 num_bytes = write (dbf->desc, dbf->bucket, dbf->header->bucket_size);
319 if (num_bytes != dbf->header->bucket_size)
320 {
321 gdbm_close (dbf);
322 gdbm_errno = GDBM_FILE_WRITE_ERROR;
323 return NULL;
324 }
325
326 /* Wait for initial configuration to be written to disk. */
327 fsync (dbf->desc);
328
329 }
330 else
331 {
332 /* This is an old database. Read in the information from the file
333 header and initialize the hash directory. */
334
335 gdbm_file_header partial_header; /* For the first part of it. */
336
337 /* Read the partial file header. */
338 num_bytes = read (dbf->desc, &partial_header, sizeof (gdbm_file_header));
339 if (num_bytes != sizeof (gdbm_file_header))
340 {
341 gdbm_close (dbf);
342 gdbm_errno = GDBM_FILE_READ_ERROR;
343 return NULL;
344 }
345
346 /* Is the magic number good? */
347 if (partial_header.header_magic != 0x13579ace)
348 {
349 gdbm_close (dbf);
350 gdbm_errno = GDBM_BAD_MAGIC_NUMBER;
351 return NULL;
352 }
353
354 /* It is a good database, read the entire header. */
355 dbf->header = (gdbm_file_header *) malloc (partial_header.block_size);
356 if (dbf->header == NULL)
357 {
358 gdbm_close (dbf);
359 gdbm_errno = GDBM_MALLOC_ERROR;
360 return NULL;
361 }
362 bcopy (&partial_header, dbf->header, sizeof (gdbm_file_header));
363 num_bytes = read (dbf->desc, &dbf->header->avail.av_table[1],
364 dbf->header->block_size-sizeof (gdbm_file_header));
365 if (num_bytes != dbf->header->block_size-sizeof (gdbm_file_header))
366 {
367 gdbm_close (dbf);
368 gdbm_errno = GDBM_FILE_READ_ERROR;
369 return NULL;
370 }
371
372 /* Allocate space for the hash table directory. */
373 dbf->dir = (off_t *) malloc (dbf->header->dir_size);
374 if (dbf->dir == NULL)
375 {
376 gdbm_close (dbf);
377 gdbm_errno = GDBM_MALLOC_ERROR;
378 return NULL;
379 }
380
381 /* Read the hash table directory. */
382 file_pos = lseek (dbf->desc, dbf->header->dir, L_SET);
383 if (file_pos != dbf->header->dir)
384 {
385 gdbm_close (dbf);
386 gdbm_errno = GDBM_FILE_SEEK_ERROR;
387 return NULL;
388 }
389
390 num_bytes = read (dbf->desc, dbf->dir, dbf->header->dir_size);
391 if (num_bytes != dbf->header->dir_size)
392 {
393 gdbm_close (dbf);
394 gdbm_errno = GDBM_FILE_READ_ERROR;
395 return NULL;
396 }
397
398 }
399
400 /* Finish initializing dbf. */
401 dbf->last_read = -1;
402 dbf->bucket = NULL;
403 dbf->bucket_dir = 0;
404 dbf->cache_entry = NULL;
405 dbf->header_changed = FALSE;
406 dbf->directory_changed = FALSE;
407 dbf->bucket_changed = FALSE;
408 dbf->second_changed = FALSE;
409
410 /* Everything is fine, return the pointer to the file
411 information structure. */
412 return dbf;
413
414}
415
416/* initialize the bucket cache. */
417int
418_gdbm_init_cache(dbf, size)
419 gdbm_file_info *dbf;
420 int size;
421{
422register int index;
423
424 if (dbf->bucket_cache == NULL)
425 {
426 dbf->bucket_cache = (cache_elem *) malloc(sizeof(cache_elem) * size);
427 if(dbf->bucket_cache == NULL)
428 {
429 gdbm_errno = GDBM_MALLOC_ERROR;
430 return(-1);
431 }
432 dbf->cache_size = size;
433
434 for(index = 0; index < size; index++)
435 {
436 (dbf->bucket_cache[index]).ca_bucket
437 = (hash_bucket *) malloc (dbf->header->bucket_size);
438 if ((dbf->bucket_cache[index]).ca_bucket == NULL)
439 {
440 gdbm_errno = GDBM_MALLOC_ERROR;
441 return(-1);
442 }
443 (dbf->bucket_cache[index]).ca_adr = 0;
444 (dbf->bucket_cache[index]).ca_changed = FALSE;
445 (dbf->bucket_cache[index]).ca_data.hash_val = -1;
446 (dbf->bucket_cache[index]).ca_data.elem_loc = -1;
447 (dbf->bucket_cache[index]).ca_data.dptr = NULL;
448 }
449 dbf->bucket = dbf->bucket_cache[0].ca_bucket;
450 dbf->cache_entry = &dbf->bucket_cache[0];
451 }
452 return(0);
453}
Note: See TracBrowser for help on using the repository browser.