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.
4 Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation,
7 GDBM is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GDBM is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
20 /* Include system configuration before all else. */
25 /* Determine our native magic number and bail if we can't. */
27 # define GDBM_MAGIC GDBM_MAGIC32
28 #elif SIZEOF_OFF_T == 8
29 # define GDBM_MAGIC GDBM_MAGIC64
31 # error "Unsupported off_t size, contact GDBM maintainer. What crazy system is this?!?"
34 /* Initialize dbm system. FILE is a pointer to the file name. If the file
35 has a size of zero bytes, a file initialization procedure is performed,
36 setting up the initial structure in the file. BLOCK_SIZE is used during
37 initialization to determine the size of various constructs. If the value
38 is less than 512, the file system blocksize is used, otherwise the value
39 of BLOCK_SIZE is used. BLOCK_SIZE is ignored if the file has previously
40 initialized. If FLAGS is set to GDBM_READ the user wants to just
41 read the database and any call to dbm_store or dbm_delete will fail. Many
42 readers can access the database at the same time. If FLAGS is set to
43 GDBM_WRITE, the user wants both read and write access to the database and
44 requires exclusive access. If FLAGS is GDBM_WRCREAT, the user wants
45 both read and write access to the database and if the database does not
46 exist, create a new one. If FLAGS is GDBM_NEWDB, the user want a
47 new database created, regardless of whether one existed, and wants read
48 and write access to the new database. Any error detected will cause a
49 return value of null and an approprate value will be in gdbm_errno. If
50 no errors occur, a pointer to the "gdbm file descriptor" will be
55 gdbm_open (const char *file, int block_size, int flags, int mode,
56 void (*fatal_func) (const char *))
58 GDBM_FILE dbf; /* The record to return. */
59 struct stat file_stat; /* Space for the stat information. */
60 int len; /* Length of the file name. */
61 off_t file_pos; /* Used with seeks. */
62 int file_block_size; /* Block size to use for a new file. */
63 int index; /* Used as a loop index. */
64 char need_trunc; /* Used with GDBM_NEWDB and locking to avoid
65 truncating a file from under a reader. */
66 int rc; /* temporary error code */
67 int fbits = 0; /* additional bits for open(2) flags */
69 /* Initialize the gdbm_errno variable. */
70 gdbm_errno = GDBM_NO_ERROR;
72 /* Allocate new info structure. */
73 dbf = (GDBM_FILE) malloc (sizeof (*dbf));
76 gdbm_errno = GDBM_MALLOC_ERROR;
80 /* Initialize some fields for known values. This is done so gdbm_close
81 will work if called before allocating some structures. */
85 dbf->bucket_cache = NULL;
88 dbf->memory_mapping = FALSE;
89 dbf->mapped_size_max = SIZE_T_MAX;
90 dbf->mapped_region = NULL;
95 /* Save name of file. */
97 dbf->name = (char *) malloc (len + 1);
98 if (dbf->name == NULL)
101 gdbm_errno = GDBM_MALLOC_ERROR;
104 strcpy (dbf->name, file);
106 /* Initialize the fatal error routine. */
107 dbf->fatal_err = fatal_func;
109 dbf->fast_write = TRUE; /* Default to setting fast_write. */
110 dbf->file_locking = TRUE; /* Default to doing file locking. */
111 dbf->central_free = FALSE; /* Default to not using central_free. */
112 dbf->coalesce_blocks = FALSE; /* Default to not coalescing blocks. */
114 /* GDBM_FAST used to determine whether or not we set fast_write. */
115 if (flags & GDBM_SYNC)
117 /* If GDBM_SYNC has been requested, don't do fast_write. */
118 dbf->fast_write = FALSE;
120 if (flags & GDBM_NOLOCK)
122 dbf->file_locking = FALSE;
124 if (flags & GDBM_CLOEXEC)
130 dbf->cloexec = FALSE;
134 switch (flags & GDBM_OPENMASK)
137 dbf->desc = open (dbf->name, O_RDONLY|fbits, 0);
141 dbf->desc = open (dbf->name, O_RDWR|fbits, 0);
145 dbf->desc = open (dbf->name, O_RDWR|O_CREAT|fbits, mode);
150 dbf->desc = open (dbf->name, O_RDWR|O_CREAT|fbits, mode);
156 SAVE_ERRNO (free (dbf->name);
158 gdbm_errno = GDBM_FILE_OPEN_ERROR;
162 /* Get the status of the file. */
163 if (fstat (dbf->desc, &file_stat))
165 SAVE_ERRNO (close (dbf->desc);
168 gdbm_errno = GDBM_FILE_STAT_ERROR;
172 /* Zero-length file can't be a reader... */
173 if (((flags & GDBM_OPENMASK) == GDBM_READER) && (file_stat.st_size == 0))
178 gdbm_errno = GDBM_EMPTY_DATABASE;
182 /* Record the kind of user. */
183 dbf->read_write = (flags & GDBM_OPENMASK);
185 /* Lock the file in the appropriate way. */
186 if (dbf->file_locking)
188 if (_gdbm_lock_file (dbf) == -1)
193 if ((flags & GDBM_OPENMASK) == GDBM_READER)
194 gdbm_errno = GDBM_CANT_BE_READER;
196 gdbm_errno = GDBM_CANT_BE_WRITER;
201 /* If we do have a write lock and it was a GDBM_NEWDB, it is
202 now time to truncate the file. */
203 if (need_trunc && file_stat.st_size != 0)
206 fstat (dbf->desc, &file_stat);
209 /* Decide if this is a new file or an old file. */
210 if (file_stat.st_size == 0)
213 /* This is a new file. Create an empty database. */
215 /* Start with the blocksize. */
216 if (block_size < 512)
217 file_block_size = STATBLKSIZE;
219 file_block_size = block_size;
221 /* Get space for the file header. It will be written to disk, so
222 make sure there's no garbage in it. */
223 dbf->header = (gdbm_file_header *) calloc (1, file_block_size);
224 if (dbf->header == NULL)
227 gdbm_errno = GDBM_MALLOC_ERROR;
231 /* Set the magic number and the block_size. */
232 dbf->header->header_magic = GDBM_MAGIC;
233 dbf->header->block_size = file_block_size;
235 /* Create the initial hash table directory. */
236 dbf->header->dir_size = 8 * sizeof (off_t);
237 dbf->header->dir_bits = 3;
238 while (dbf->header->dir_size < dbf->header->block_size)
240 dbf->header->dir_size <<= 1;
241 dbf->header->dir_bits += 1;
244 /* Check for correct block_size. */
245 if (dbf->header->dir_size != dbf->header->block_size)
248 gdbm_errno = GDBM_BLOCK_SIZE_ERROR;
252 /* Allocate the space for the directory. */
253 dbf->dir = (off_t *) malloc (dbf->header->dir_size);
254 if (dbf->dir == NULL)
257 gdbm_errno = GDBM_MALLOC_ERROR;
260 dbf->header->dir = dbf->header->block_size;
262 /* Create the first and only hash bucket. */
263 dbf->header->bucket_elems =
264 (dbf->header->block_size - sizeof (hash_bucket))
265 / sizeof (bucket_element) + 1;
266 dbf->header->bucket_size = dbf->header->block_size;
267 dbf->bucket = (hash_bucket *) malloc (dbf->header->bucket_size);
268 if (dbf->bucket == NULL)
271 gdbm_errno = GDBM_MALLOC_ERROR;
274 _gdbm_new_bucket (dbf, dbf->bucket, 0);
275 dbf->bucket->av_count = 1;
276 dbf->bucket->bucket_avail[0].av_adr = 3*dbf->header->block_size;
277 dbf->bucket->bucket_avail[0].av_size = dbf->header->block_size;
279 /* Set table entries to point to hash buckets. */
280 for (index = 0; index < GDBM_DIR_COUNT (dbf); index++)
281 dbf->dir[index] = 2*dbf->header->block_size;
283 /* Initialize the active avail block. */
284 dbf->header->avail.size
285 = ( (dbf->header->block_size - sizeof (gdbm_file_header))
286 / sizeof (avail_elem)) + 1;
287 dbf->header->avail.count = 0;
288 dbf->header->avail.next_block = 0;
289 dbf->header->next_block = 4*dbf->header->block_size;
291 /* Write initial configuration to the file. */
292 /* Block 0 is the file header and active avail block. */
293 rc = _gdbm_full_write (dbf, dbf->header, dbf->header->block_size);
296 SAVE_ERRNO (gdbm_close (dbf));
301 /* Block 1 is the initial bucket directory. */
302 rc = _gdbm_full_write (dbf, dbf->dir, dbf->header->dir_size);
305 SAVE_ERRNO (gdbm_close (dbf));
310 /* Block 2 is the only bucket. */
311 rc = _gdbm_full_write (dbf, dbf->bucket, dbf->header->bucket_size);
314 SAVE_ERRNO (gdbm_close (dbf));
319 /* Wait for initial configuration to be written to disk. */
326 /* This is an old database. Read in the information from the file
327 header and initialize the hash directory. */
329 gdbm_file_header partial_header; /* For the first part of it. */
331 /* Read the partial file header. */
332 rc = _gdbm_full_read (dbf, &partial_header, sizeof (gdbm_file_header));
335 SAVE_ERRNO (gdbm_close (dbf));
340 /* Is the magic number good? */
341 if (partial_header.header_magic != GDBM_MAGIC
342 && partial_header.header_magic != GDBM_OMAGIC)
345 switch (partial_header.header_magic)
347 case GDBM_OMAGIC_SWAP:
348 case GDBM_MAGIC32_SWAP:
349 case GDBM_MAGIC64_SWAP:
350 gdbm_errno = GDBM_BYTE_SWAPPED;
354 gdbm_errno = GDBM_BAD_FILE_OFFSET;
357 gdbm_errno = GDBM_BAD_MAGIC_NUMBER;
362 /* It is a good database, read the entire header. */
363 dbf->header = (gdbm_file_header *) malloc (partial_header.block_size);
364 if (dbf->header == NULL)
367 gdbm_errno = GDBM_MALLOC_ERROR;
370 memcpy (dbf->header, &partial_header, sizeof (gdbm_file_header));
371 rc = _gdbm_full_read (dbf, &dbf->header->avail.av_table[1],
372 dbf->header->block_size-sizeof (gdbm_file_header));
375 SAVE_ERRNO (gdbm_close (dbf));
380 /* Allocate space for the hash table directory. */
381 dbf->dir = (off_t *) malloc (dbf->header->dir_size);
382 if (dbf->dir == NULL)
385 gdbm_errno = GDBM_MALLOC_ERROR;
389 /* Read the hash table directory. */
390 file_pos = __lseek (dbf, dbf->header->dir, SEEK_SET);
391 if (file_pos != dbf->header->dir)
393 SAVE_ERRNO (gdbm_close (dbf));
394 gdbm_errno = GDBM_FILE_SEEK_ERROR;
398 rc = _gdbm_full_read (dbf, dbf->dir, dbf->header->dir_size);
401 SAVE_ERRNO (gdbm_close (dbf));
409 if (!(flags & GDBM_NOMMAP))
411 if (_gdbm_mapped_init (dbf) == 0)
412 dbf->memory_mapping = TRUE;
415 /* gdbm_errno should already be set. */
424 /* Finish initializing dbf. */
428 dbf->cache_entry = NULL;
429 dbf->header_changed = FALSE;
430 dbf->directory_changed = FALSE;
431 dbf->bucket_changed = FALSE;
432 dbf->second_changed = FALSE;
434 /* Everything is fine, return the pointer to the file
435 information structure. */
440 /* Initialize the bucket cache. */
442 _gdbm_init_cache(GDBM_FILE dbf, size_t size)
446 if (dbf->bucket_cache == NULL)
448 dbf->bucket_cache = (cache_elem *) malloc(sizeof(cache_elem) * size);
449 if(dbf->bucket_cache == NULL)
451 gdbm_errno = GDBM_MALLOC_ERROR;
454 dbf->cache_size = size;
456 for(index = 0; index < size; index++)
458 (dbf->bucket_cache[index]).ca_bucket
459 = (hash_bucket *) malloc (dbf->header->bucket_size);
460 if ((dbf->bucket_cache[index]).ca_bucket == NULL)
462 gdbm_errno = GDBM_MALLOC_ERROR;
465 (dbf->bucket_cache[index]).ca_adr = 0;
466 (dbf->bucket_cache[index]).ca_changed = FALSE;
467 (dbf->bucket_cache[index]).ca_data.hash_val = -1;
468 (dbf->bucket_cache[index]).ca_data.elem_loc = -1;
469 (dbf->bucket_cache[index]).ca_data.dptr = NULL;
471 dbf->bucket = dbf->bucket_cache[0].ca_bucket;
472 dbf->cache_entry = &dbf->bucket_cache[0];