Fixed license declaration at spec file
[platform/upstream/gdbm.git] / src / gdbmopen.c
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.
4    Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation,
5    Inc.
6
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)
10    any later version.
11
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.
16
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/>.   */
19
20 /* Include system configuration before all else. */
21 #include "autoconf.h"
22
23 #include "gdbmdefs.h"
24
25 /* Determine our native magic number and bail if we can't. */
26 #if SIZEOF_OFF_T == 4
27 # define GDBM_MAGIC     GDBM_MAGIC32
28 #elif SIZEOF_OFF_T == 8
29 # define GDBM_MAGIC     GDBM_MAGIC64
30 #else
31 # error "Unsupported off_t size, contact GDBM maintainer.  What crazy system is this?!?"
32 #endif
33
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
51    returned. */
52    
53
54 GDBM_FILE 
55 gdbm_open (const char *file, int block_size, int flags, int mode,
56            void (*fatal_func) (const char *))
57 {
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 */
68   
69   /* Initialize the gdbm_errno variable. */
70   gdbm_errno = GDBM_NO_ERROR;
71
72   /* Allocate new info structure. */
73   dbf = (GDBM_FILE) malloc (sizeof (*dbf));
74   if (dbf == NULL)
75     {
76       gdbm_errno = GDBM_MALLOC_ERROR;
77       return NULL;
78     }
79
80   /* Initialize some fields for known values.  This is done so gdbm_close
81      will work if called before allocating some structures. */
82   dbf->dir  = NULL;
83   dbf->bucket = NULL;
84   dbf->header = NULL;
85   dbf->bucket_cache = NULL;
86   dbf->cache_size = 0;
87
88   dbf->memory_mapping = FALSE;
89   dbf->mapped_size_max = SIZE_T_MAX;
90   dbf->mapped_region = NULL;
91   dbf->mapped_size = 0;
92   dbf->mapped_pos = 0;
93   dbf->mapped_off = 0;
94   
95   /* Save name of file. */
96   len = strlen (file);
97   dbf->name = (char *) malloc (len + 1);
98   if (dbf->name == NULL)
99     {
100       free (dbf);
101       gdbm_errno = GDBM_MALLOC_ERROR;
102       return NULL;
103     }
104   strcpy (dbf->name, file);
105
106   /* Initialize the fatal error routine. */
107   dbf->fatal_err = fatal_func;
108
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. */
113   
114   /* GDBM_FAST used to determine whether or not we set fast_write. */
115   if (flags & GDBM_SYNC)
116     {
117       /* If GDBM_SYNC has been requested, don't do fast_write. */
118       dbf->fast_write = FALSE;
119     }
120   if (flags & GDBM_NOLOCK)
121     {
122       dbf->file_locking = FALSE;
123     }
124   if (flags & GDBM_CLOEXEC)
125     {
126       fbits = O_CLOEXEC;
127       dbf->cloexec = TRUE;
128     }
129   else
130     dbf->cloexec = FALSE;
131   
132   /* Open the file. */
133   need_trunc = FALSE;
134   switch (flags & GDBM_OPENMASK)
135     {
136       case GDBM_READER:
137         dbf->desc = open (dbf->name, O_RDONLY|fbits, 0);
138         break;
139
140       case GDBM_WRITER:
141         dbf->desc = open (dbf->name, O_RDWR|fbits, 0);
142         break;
143
144       case GDBM_NEWDB:
145         dbf->desc = open (dbf->name, O_RDWR|O_CREAT|fbits, mode);
146         need_trunc = TRUE;
147         break;
148
149       default:
150         dbf->desc = open (dbf->name, O_RDWR|O_CREAT|fbits, mode);
151         break;
152
153     }
154   if (dbf->desc < 0)
155     {
156       SAVE_ERRNO (free (dbf->name);
157                   free (dbf));
158       gdbm_errno = GDBM_FILE_OPEN_ERROR;
159       return NULL;
160     }
161
162   /* Get the status of the file. */
163   if (fstat (dbf->desc, &file_stat))
164     {
165       SAVE_ERRNO (close (dbf->desc);
166                   free (dbf->name);
167                   free (dbf));
168       gdbm_errno = GDBM_FILE_STAT_ERROR;
169       return NULL;
170     }
171   
172   /* Zero-length file can't be a reader... */
173   if (((flags & GDBM_OPENMASK) == GDBM_READER) && (file_stat.st_size == 0))
174     {
175       close (dbf->desc);
176       free (dbf->name);
177       free (dbf);
178       gdbm_errno = GDBM_EMPTY_DATABASE;
179       return NULL;
180     }
181
182   /* Record the kind of user. */
183   dbf->read_write = (flags & GDBM_OPENMASK);
184
185   /* Lock the file in the appropriate way. */
186   if (dbf->file_locking)
187     {
188       if (_gdbm_lock_file (dbf) == -1)
189         {
190           close (dbf->desc);
191           free (dbf->name);
192           free (dbf);
193           if ((flags & GDBM_OPENMASK) == GDBM_READER)
194             gdbm_errno = GDBM_CANT_BE_READER;
195           else
196             gdbm_errno = GDBM_CANT_BE_WRITER;
197           return NULL;
198         }
199     }
200
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)
204     {
205       TRUNCATE (dbf);
206       fstat (dbf->desc, &file_stat);
207     }
208
209   /* Decide if this is a new file or an old file. */
210   if (file_stat.st_size == 0)
211     {
212
213       /* This is a new file.  Create an empty database.  */
214
215       /* Start with the blocksize. */
216       if (block_size < 512)
217         file_block_size = STATBLKSIZE;
218       else
219         file_block_size = block_size;
220
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)
225         {
226           gdbm_close (dbf);
227           gdbm_errno = GDBM_MALLOC_ERROR;
228           return NULL;
229         }
230
231       /* Set the magic number and the block_size. */
232       dbf->header->header_magic = GDBM_MAGIC;
233       dbf->header->block_size = file_block_size;
234      
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)
239         {
240           dbf->header->dir_size <<= 1;
241           dbf->header->dir_bits += 1;
242         }
243
244       /* Check for correct block_size. */
245       if (dbf->header->dir_size != dbf->header->block_size)
246         {
247           gdbm_close (dbf);
248           gdbm_errno = GDBM_BLOCK_SIZE_ERROR;
249           return NULL;
250         }
251
252       /* Allocate the space for the directory. */
253       dbf->dir = (off_t *) malloc (dbf->header->dir_size);
254       if (dbf->dir == NULL)
255         {
256           gdbm_close (dbf);
257           gdbm_errno = GDBM_MALLOC_ERROR;
258           return NULL;
259         }
260       dbf->header->dir = dbf->header->block_size;
261
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)
269         {
270           gdbm_close (dbf);
271           gdbm_errno = GDBM_MALLOC_ERROR;
272           return NULL;
273         }
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;
278
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;
282
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;
290
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);
294       if (rc)
295         {
296           SAVE_ERRNO (gdbm_close (dbf));
297           gdbm_errno = rc;
298           return NULL;
299         }
300
301       /* Block 1 is the initial bucket directory. */
302       rc = _gdbm_full_write (dbf, dbf->dir, dbf->header->dir_size);
303       if (rc)
304         {
305           SAVE_ERRNO (gdbm_close (dbf));
306           gdbm_errno = rc;
307           return NULL;
308         }
309
310       /* Block 2 is the only bucket. */
311       rc = _gdbm_full_write (dbf, dbf->bucket, dbf->header->bucket_size);
312       if (rc)
313         {
314           SAVE_ERRNO (gdbm_close (dbf));
315           gdbm_errno = rc;
316           return NULL;
317         }
318
319       /* Wait for initial configuration to be written to disk. */
320       __fsync (dbf);
321
322       free (dbf->bucket);
323     }
324   else
325     {
326       /* This is an old database.  Read in the information from the file
327          header and initialize the hash directory. */
328
329       gdbm_file_header partial_header;  /* For the first part of it. */
330
331       /* Read the partial file header. */
332       rc = _gdbm_full_read (dbf, &partial_header, sizeof (gdbm_file_header));
333       if (rc)
334         {
335           SAVE_ERRNO (gdbm_close (dbf));
336           gdbm_errno = rc;
337           return NULL;
338         }
339
340       /* Is the magic number good? */
341       if (partial_header.header_magic != GDBM_MAGIC
342           && partial_header.header_magic != GDBM_OMAGIC)
343         {
344           gdbm_close (dbf);
345           switch (partial_header.header_magic)
346             {
347               case GDBM_OMAGIC_SWAP:
348               case GDBM_MAGIC32_SWAP:
349               case GDBM_MAGIC64_SWAP:
350                 gdbm_errno = GDBM_BYTE_SWAPPED;
351                 break;
352               case GDBM_MAGIC32:
353               case GDBM_MAGIC64:
354                 gdbm_errno = GDBM_BAD_FILE_OFFSET;
355                 break;
356               default:
357                 gdbm_errno = GDBM_BAD_MAGIC_NUMBER;
358             }
359           return NULL;
360         }
361
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)
365         {
366           gdbm_close (dbf);
367           gdbm_errno = GDBM_MALLOC_ERROR;
368           return NULL;
369         }
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));
373       if (rc)
374         {
375           SAVE_ERRNO (gdbm_close (dbf));
376           gdbm_errno = rc;
377           return NULL;
378         }
379         
380       /* Allocate space for the hash table directory.  */
381       dbf->dir = (off_t *) malloc (dbf->header->dir_size);
382       if (dbf->dir == NULL)
383         {
384           gdbm_close (dbf);
385           gdbm_errno = GDBM_MALLOC_ERROR;
386           return NULL;
387         }
388
389       /* Read the hash table directory. */
390       file_pos = __lseek (dbf, dbf->header->dir, SEEK_SET);
391       if (file_pos != dbf->header->dir)
392         {
393           SAVE_ERRNO (gdbm_close (dbf));
394           gdbm_errno = GDBM_FILE_SEEK_ERROR;
395           return NULL;
396         }
397
398       rc = _gdbm_full_read (dbf, dbf->dir, dbf->header->dir_size);
399       if (rc)
400         {
401           SAVE_ERRNO (gdbm_close (dbf));
402           gdbm_errno = rc;
403           return NULL;
404         }
405
406     }
407
408 #if HAVE_MMAP
409   if (!(flags & GDBM_NOMMAP))
410     {
411       if (_gdbm_mapped_init (dbf) == 0)
412         dbf->memory_mapping = TRUE;
413       else
414         {
415           /* gdbm_errno should already be set. */
416           close (dbf->desc);
417           free (dbf->name);
418           free (dbf);
419           return NULL;
420         }
421     }
422 #endif
423
424   /* Finish initializing dbf. */
425   dbf->last_read = -1;
426   dbf->bucket = NULL;
427   dbf->bucket_dir = 0;
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;
433   
434   /* Everything is fine, return the pointer to the file
435      information structure.  */
436   return dbf;
437
438 }
439
440 /* Initialize the bucket cache. */
441 int
442 _gdbm_init_cache(GDBM_FILE dbf, size_t size)
443 {
444   int index;
445
446   if (dbf->bucket_cache == NULL)
447     {
448       dbf->bucket_cache = (cache_elem *) malloc(sizeof(cache_elem) * size);
449       if(dbf->bucket_cache == NULL)
450         {
451           gdbm_errno = GDBM_MALLOC_ERROR;
452           return -1;
453         }
454       dbf->cache_size = size;
455
456       for(index = 0; index < size; index++)
457         {
458           (dbf->bucket_cache[index]).ca_bucket
459             = (hash_bucket *) malloc (dbf->header->bucket_size);
460           if ((dbf->bucket_cache[index]).ca_bucket == NULL)
461             {
462               gdbm_errno = GDBM_MALLOC_ERROR;
463               return -1;
464             }
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;
470         }
471       dbf->bucket = dbf->bucket_cache[0].ca_bucket;
472       dbf->cache_entry = &dbf->bucket_cache[0];
473     }
474   return 0;
475 }