source: gsdl/trunk/common-src/packages/gdbm/gdbm-1.8.3/gdbmopen.c@ 18019

Last change on this file since 18019 was 18019, checked in by mdewsnip, 15 years ago

Added gdbm-1.8.3 (downloaded as gdbm-1.8.3.tar.gz and unpacked), in preparation for adding code for reading both little and big endian databases.

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