1
/* gdbmopen.c - Open the dbm file and initialize data structures for use. */
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.
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)
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.
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.
20
You may contact the author by:
21
e-mail: phil@cs.wwu.edu
22
us-mail: Philip A. Nelson
23
Computer Science Department
24
Western Washington University
27
*************************************************************************/
30
/* include system configuration before all else. */
34
#include "gdbmerrno.h"
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
57
gdbm_open (file, block_size, flags, mode, fatal_func)
62
void (*fatal_func) ();
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. */
75
/* Initialize the gdbm_errno variable. */
76
gdbm_errno = GDBM_NO_ERROR;
78
/* Allocate new info structure. */
79
dbf = (gdbm_file_info *) malloc (sizeof (gdbm_file_info));
82
gdbm_errno = GDBM_MALLOC_ERROR;
86
/* Initialize some fields for known values. This is done so gdbm_close
87
will work if called before allocating some structures. */
91
dbf->bucket_cache = NULL;
94
/* Save name of file. */
96
dbf->name = (char *) malloc (len + 1);
97
if (dbf->name == NULL)
100
gdbm_errno = GDBM_MALLOC_ERROR;
103
strcpy (dbf->name, file);
105
/* Initialize the fatal error routine. */
106
dbf->fatal_err = fatal_func;
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. */
113
/* GDBM_FAST used to determine whethere or not we set fast_write. */
114
if (flags & GDBM_SYNC)
116
/* If GDBM_SYNC has been requested, don't do fast_write. */
117
dbf->fast_write = FALSE;
119
if (flags & GDBM_NOLOCK)
121
dbf->file_locking = FALSE;
126
switch (flags & GDBM_OPENMASK)
129
dbf->desc = open (dbf->name, O_RDONLY, 0);
133
dbf->desc = open (dbf->name, O_RDWR, 0);
137
dbf->desc = open (dbf->name, O_RDWR|O_CREAT, mode);
143
dbf->desc = open (dbf->name, O_RDWR|O_CREAT, mode);
152
gdbm_errno = GDBM_FILE_OPEN_ERROR;
156
/* Get the status of the file. */
157
fstat (dbf->desc, &file_stat);
159
/* Lock the file in the approprate way. */
160
if ((flags & GDBM_OPENMASK) == GDBM_READER)
162
if (file_stat.st_size == 0)
167
gdbm_errno = GDBM_EMPTY_DATABASE;
170
if (dbf->file_locking)
172
/* Sets lock_val to 0 for success. See systems.h. */
176
else if (dbf->file_locking)
178
/* Sets lock_val to 0 for success. See systems.h. */
181
if (dbf->file_locking && (lock_val != 0))
186
if ((flags & GDBM_OPENMASK) == GDBM_READER)
187
gdbm_errno = GDBM_CANT_BE_READER;
189
gdbm_errno = GDBM_CANT_BE_WRITER;
193
/* Record the kind of user. */
194
dbf->read_write = (flags & GDBM_OPENMASK);
196
/* If we do have a write lock and it was a GDBM_NEWDB, it is
197
now time to truncate the file. */
198
if (need_trunc && file_stat.st_size != 0)
201
fstat (dbf->desc, &file_stat);
204
/* Decide if this is a new file or an old file. */
205
if (file_stat.st_size == 0)
208
/* This is a new file. Create an empty database. */
210
/* Start with the blocksize. */
211
if (block_size < 512)
212
file_block_size = STATBLKSIZE;
214
file_block_size = block_size;
216
/* Get space for the file header. */
217
dbf->header = (gdbm_file_header *) malloc (file_block_size);
218
if (dbf->header == NULL)
221
gdbm_errno = GDBM_MALLOC_ERROR;
225
/* Set the magic number and the block_size. */
226
dbf->header->header_magic = 0x13579ace;
227
dbf->header->block_size = file_block_size;
229
/* Create the initial hash table directory. */
230
dbf->header->dir_size = 8 * sizeof (off_t);
231
dbf->header->dir_bits = 3;
232
while (dbf->header->dir_size < dbf->header->block_size)
234
dbf->header->dir_size <<= 1;
235
dbf->header->dir_bits += 1;
238
/* Check for correct block_size. */
239
if (dbf->header->dir_size != dbf->header->block_size)
242
gdbm_errno = GDBM_BLOCK_SIZE_ERROR;
246
/* Allocate the space for the directory. */
247
dbf->dir = (off_t *) malloc (dbf->header->dir_size);
248
if (dbf->dir == NULL)
251
gdbm_errno = GDBM_MALLOC_ERROR;
254
dbf->header->dir = dbf->header->block_size;
256
/* Create the first and only hash bucket. */
257
dbf->header->bucket_elems =
258
(dbf->header->block_size - sizeof (hash_bucket))
259
/ sizeof (bucket_element) + 1;
260
dbf->header->bucket_size = dbf->header->block_size;
261
dbf->bucket = (hash_bucket *) malloc (dbf->header->bucket_size);
262
if (dbf->bucket == NULL)
265
gdbm_errno = GDBM_MALLOC_ERROR;
268
_gdbm_new_bucket (dbf, dbf->bucket, 0);
269
dbf->bucket->av_count = 1;
270
dbf->bucket->bucket_avail[0].av_adr = 3*dbf->header->block_size;
271
dbf->bucket->bucket_avail[0].av_size = dbf->header->block_size;
273
/* Set table entries to point to hash buckets. */
274
for (index = 0; index < dbf->header->dir_size / sizeof (off_t); index++)
275
dbf->dir[index] = 2*dbf->header->block_size;
277
/* Initialize the active avail block. */
278
dbf->header->avail.size
279
= ( (dbf->header->block_size - sizeof (gdbm_file_header))
280
/ sizeof (avail_elem)) + 1;
281
dbf->header->avail.count = 0;
282
dbf->header->avail.next_block = 0;
283
dbf->header->next_block = 4*dbf->header->block_size;
285
/* Write initial configuration to the file. */
286
/* Block 0 is the file header and active avail block. */
287
num_bytes = write (dbf->desc, dbf->header, dbf->header->block_size);
288
if (num_bytes != dbf->header->block_size)
291
gdbm_errno = GDBM_FILE_WRITE_ERROR;
295
/* Block 1 is the initial bucket directory. */
296
num_bytes = write (dbf->desc, dbf->dir, dbf->header->dir_size);
297
if (num_bytes != dbf->header->dir_size)
300
gdbm_errno = GDBM_FILE_WRITE_ERROR;
304
/* Block 2 is the only bucket. */
305
num_bytes = write (dbf->desc, dbf->bucket, dbf->header->bucket_size);
306
if (num_bytes != dbf->header->bucket_size)
309
gdbm_errno = GDBM_FILE_WRITE_ERROR;
313
/* Wait for initial configuration to be written to disk. */
320
/* This is an old database. Read in the information from the file
321
header and initialize the hash directory. */
323
gdbm_file_header partial_header; /* For the first part of it. */
325
/* Read the partial file header. */
326
num_bytes = read (dbf->desc, &partial_header, sizeof (gdbm_file_header));
327
if (num_bytes != sizeof (gdbm_file_header))
330
gdbm_errno = GDBM_FILE_READ_ERROR;
334
/* Is the magic number good? */
335
if (partial_header.header_magic != 0x13579ace)
338
gdbm_errno = GDBM_BAD_MAGIC_NUMBER;
342
/* It is a good database, read the entire header. */
343
dbf->header = (gdbm_file_header *) malloc (partial_header.block_size);
344
if (dbf->header == NULL)
347
gdbm_errno = GDBM_MALLOC_ERROR;
350
bcopy (&partial_header, dbf->header, sizeof (gdbm_file_header));
351
num_bytes = read (dbf->desc, &dbf->header->avail.av_table[1],
352
dbf->header->block_size-sizeof (gdbm_file_header));
353
if (num_bytes != dbf->header->block_size-sizeof (gdbm_file_header))
356
gdbm_errno = GDBM_FILE_READ_ERROR;
360
/* Allocate space for the hash table directory. */
361
dbf->dir = (off_t *) malloc (dbf->header->dir_size);
362
if (dbf->dir == NULL)
365
gdbm_errno = GDBM_MALLOC_ERROR;
369
/* Read the hash table directory. */
370
file_pos = lseek (dbf->desc, dbf->header->dir, L_SET);
371
if (file_pos != dbf->header->dir)
374
gdbm_errno = GDBM_FILE_SEEK_ERROR;
378
num_bytes = read (dbf->desc, dbf->dir, dbf->header->dir_size);
379
if (num_bytes != dbf->header->dir_size)
382
gdbm_errno = GDBM_FILE_READ_ERROR;
388
/* Finish initializing dbf. */
392
dbf->cache_entry = NULL;
393
dbf->header_changed = FALSE;
394
dbf->directory_changed = FALSE;
395
dbf->bucket_changed = FALSE;
396
dbf->second_changed = FALSE;
398
/* Everything is fine, return the pointer to the file
399
information structure. */
404
/* initialize the bucket cache. */
406
_gdbm_init_cache(dbf, size)
412
if (dbf->bucket_cache == NULL)
414
dbf->bucket_cache = (cache_elem *) malloc(sizeof(cache_elem) * size);
415
if(dbf->bucket_cache == NULL)
417
gdbm_errno = GDBM_MALLOC_ERROR;
420
dbf->cache_size = size;
422
for(index = 0; index < size; index++)
424
(dbf->bucket_cache[index]).ca_bucket
425
= (hash_bucket *) malloc (dbf->header->bucket_size);
426
if ((dbf->bucket_cache[index]).ca_bucket == NULL)
428
gdbm_errno = GDBM_MALLOC_ERROR;
431
(dbf->bucket_cache[index]).ca_adr = 0;
432
(dbf->bucket_cache[index]).ca_changed = FALSE;
433
(dbf->bucket_cache[index]).ca_data.hash_val = -1;
434
(dbf->bucket_cache[index]).ca_data.elem_loc = -1;
435
(dbf->bucket_cache[index]).ca_data.dptr = NULL;
437
dbf->bucket = dbf->bucket_cache[0].ca_bucket;
438
dbf->cache_entry = &dbf->bucket_cache[0];