diff options
-rw-r--r-- | compat/dbminit.c | 2 | ||||
-rw-r--r-- | compat/dbmopen.c | 4 | ||||
-rw-r--r-- | src/gdbm.h.in | 3 | ||||
-rw-r--r-- | src/gdbmcount.c | 3 | ||||
-rw-r--r-- | src/gdbmdefs.h | 274 | ||||
-rw-r--r-- | src/gdbmdelete.c | 4 | ||||
-rw-r--r-- | src/gdbmdump.c | 6 | ||||
-rw-r--r-- | src/gdbmerrno.c | 3 | ||||
-rw-r--r-- | src/gdbmexists.c | 3 | ||||
-rw-r--r-- | src/gdbmexp.c | 3 | ||||
-rw-r--r-- | src/gdbmfetch.c | 3 | ||||
-rw-r--r-- | src/gdbmimp.c | 3 | ||||
-rw-r--r-- | src/gdbmopen.c | 3 | ||||
-rw-r--r-- | src/gdbmreorg.c | 2 | ||||
-rw-r--r-- | src/gdbmseq.c | 12 | ||||
-rw-r--r-- | src/gdbmsetopt.c | 3 | ||||
-rw-r--r-- | src/gdbmstore.c | 5 | ||||
-rw-r--r-- | src/gdbmsync.c | 2 |
18 files changed, 201 insertions, 137 deletions
diff --git a/compat/dbminit.c b/compat/dbminit.c index f5c5a65..f5203d1 100644 --- a/compat/dbminit.c +++ b/compat/dbminit.c @@ -2,7 +2,7 @@ DBM interface. */ /* This file is part of GDBM, the GNU data base manager. - Copyright (C) 1990, 1991, 1993, 2007, 2011 Free Software Foundation, + Copyright (C) 1990, 1991, 1993, 2007, 2011, 2016 Free Software Foundation, Inc. GDBM is free software; you can redistribute it and/or modify diff --git a/compat/dbmopen.c b/compat/dbmopen.c index f8df3e3..af423df 100644 --- a/compat/dbmopen.c +++ b/compat/dbmopen.c @@ -2,7 +2,7 @@ NDBM interface for dbm use. */ /* This file is part of GDBM, the GNU data base manager. - Copyright (C) 1990, 1991, 1993, 2007, 2011 Free Software Foundation, + Copyright (C) 1990, 1991, 1993, 2007, 2011, 2016 Free Software Foundation, Inc. GDBM is free software; you can redistribute it and/or modify @@ -259,7 +259,7 @@ dbm_open (char *file, int flags, int mode) /* Did we successfully open the file? */ if (dbm->file == NULL) { - gdbm_set_errno (dbm, GDBM_FILE_OPEN_ERROR, 1); + gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, 1); free (dbm); dbm = NULL; } diff --git a/src/gdbm.h.in b/src/gdbm.h.in index 9a027dc..83f99c2 100644 --- a/src/gdbm.h.in +++ b/src/gdbm.h.in @@ -171,9 +171,10 @@ extern int gdbm_load_from_file (GDBM_FILE *, FILE *, int replace, # define GDBM_NO_DBNAME 26 # define GDBM_ERR_FILE_OWNER 27 # define GDBM_ERR_FILE_MODE 28 +# define GDBM_NEED_RECOVERY 29 # define _GDBM_MIN_ERRNO 0 -# define _GDBM_MAX_ERRNO GDBM_ERR_FILE_MODE +# define _GDBM_MAX_ERRNO GDBM_NEED_RECOVERY typedef int gdbm_error; /* For compatibilities sake. */ extern gdbm_error gdbm_errno; diff --git a/src/gdbmcount.c b/src/gdbmcount.c index 17016b2..472f0d3 100644 --- a/src/gdbmcount.c +++ b/src/gdbmcount.c @@ -39,6 +39,9 @@ gdbm_count (GDBM_FILE dbf, gdbm_count_t *pcount) off_t *sdir; gdbm_count_t count = 0; int i, last; + + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, -1); sdir = malloc (dbf->header->dir_size); if (!sdir) diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h index e873117..34c8b55 100644 --- a/src/gdbmdefs.h +++ b/src/gdbmdefs.h @@ -1,8 +1,8 @@ /* gdbmdefs.h - The include file for dbm. Defines structure and constants. */ /* This file is part of GDBM, the GNU data base manager. - Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation, - Inc. + Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013, + 2016 Free Software Foundation, Inc. GDBM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,36 +35,39 @@ not empty, the top of the stack is popped into the active avail table. */ /* The following structure is the element of the avaliable table. */ -typedef struct { - int av_size; /* The size of the available block. */ - off_t av_adr; /* The file address of the available block. */ - } avail_elem; +typedef struct +{ + int av_size; /* The size of the available block. */ + off_t av_adr; /* The file address of the available block. */ +} avail_elem; /* This is the actual table. The in-memory images of the avail blocks are allocated by malloc using a calculated size. */ -typedef struct { - int size; /* The number of avail elements in the table.*/ - int count; /* The number of entries in the table. */ - off_t next_block; /* The file address of the next avail block. */ - avail_elem av_table[1]; /* The table. Make it look like an array. */ - } avail_block; +typedef struct +{ + int size; /* The number of avail elements in the table.*/ + int count; /* The number of entries in the table. */ + off_t next_block; /* The file address of the next avail block. */ + avail_elem av_table[1]; /* The table. Make it look like an array. */ +} avail_block; /* The dbm file header keeps track of the current location of the hash directory and the free space in the file. */ -typedef struct { - int header_magic; /* Version of file. */ - int block_size; /* The optimal i/o blocksize from stat. */ - off_t dir; /* File address of hash directory table. */ - int dir_size; /* Size in bytes of the table. */ - int dir_bits; /* The number of address bits used in the table.*/ - int bucket_size; /* Size in bytes of a hash bucket struct. */ - int bucket_elems; /* Number of elements in a hash bucket. */ - off_t next_block; /* The next unallocated block address. */ - avail_block avail; /* This must be last because of the pseudo - array in avail. This avail grows to fill - the entire block. */ - } gdbm_file_header; +typedef struct +{ + int header_magic; /* Version of file. */ + int block_size; /* The optimal i/o blocksize from stat. */ + off_t dir; /* File address of hash directory table. */ + int dir_size; /* Size in bytes of the table. */ + int dir_bits; /* The number of address bits used in the table.*/ + int bucket_size; /* Size in bytes of a hash bucket struct. */ + int bucket_elems; /* Number of elements in a hash bucket. */ + off_t next_block; /* The next unallocated block address. */ + avail_block avail; /* This must be last because of the pseudo + array in avail. This avail grows to fill + the entire block. */ +} gdbm_file_header; /* The dbm hash bucket element contains the full 31 bit hash value, the @@ -73,14 +76,15 @@ typedef struct { part of the key has the correct value without having to read the actual key. */ -typedef struct { - int hash_value; /* The complete 31 bit value. */ - char key_start[SMALL]; /* Up to the first SMALL bytes of the key. */ - off_t data_pointer; /* The file address of the key record. The - data record directly follows the key. */ - int key_size; /* Size of key data in the file. */ - int data_size; /* Size of associated data in the file. */ - } bucket_element; +typedef struct +{ + int hash_value; /* The complete 31 bit value. */ + char key_start[SMALL]; /* Up to the first SMALL bytes of the key. */ + off_t data_pointer; /* The file address of the key record. The + data record directly follows the key. */ + int key_size; /* Size of key data in the file. */ + int data_size; /* Size of associated data in the file. */ +} bucket_element; /* A bucket is a small hash table. This one consists of a number of @@ -95,13 +99,14 @@ typedef struct { the file system buffer size. To speed up write, each bucket will have BUCKET_AVAIL avail elements with the bucket. */ -typedef struct { - int av_count; /* The number of bucket_avail entries. */ - avail_elem bucket_avail[BUCKET_AVAIL]; /* Distributed avail. */ - int bucket_bits; /* The number of bits used to get here. */ - int count; /* The number of element buckets full. */ - bucket_element h_table[1]; /* The table. Make it look like an array.*/ - } hash_bucket; +typedef struct +{ + int av_count; /* The number of bucket_avail entries. */ + avail_elem bucket_avail[BUCKET_AVAIL]; /* Distributed avail. */ + int bucket_bits; /* The number of bits used to get here. */ + int count; /* The number of element buckets full. */ + bucket_element h_table[1]; /* The table. Make it look like an array.*/ +} hash_bucket; /* We want to keep from reading buckets as much as possible. The following is to implement a bucket cache. When full, buckets will be dropped in a @@ -114,118 +119,133 @@ typedef struct { in a data cache. Each bucket cached will have a one element data cache. */ -typedef struct { - int hash_val; - int data_size; - int key_size; - char *dptr; - int elem_loc; - } data_cache_elem; - -typedef struct { - hash_bucket * ca_bucket; - off_t ca_adr; - char ca_changed; /* Data in the bucket changed. */ - data_cache_elem ca_data; - } cache_elem; +typedef struct +{ + int hash_val; + int data_size; + int key_size; + char *dptr; + int elem_loc; +} data_cache_elem; + +typedef struct +{ + hash_bucket * ca_bucket; + off_t ca_adr; + char ca_changed; /* Data in the bucket changed. */ + data_cache_elem ca_data; +} cache_elem; /* This final structure contains all main memory based information for a gdbm file. This allows multiple gdbm files to be opened at the same time by one program. */ -struct gdbm_file_info { - /* Global variables and pointers to dynamic variables used by gdbm. */ +struct gdbm_file_info +{ + /* Global variables and pointers to dynamic variables used by gdbm. */ - /* The file name. */ - char *name; + /* The file name. */ + char *name; - /* The reader/writer status. */ - unsigned read_write :2; + /* The reader/writer status. */ + unsigned read_write :2; - /* Fast_write is set to 1 if no fsyncs are to be done. */ - unsigned fast_write :1; + /* Fast_write is set to 1 if no fsyncs are to be done. */ + unsigned fast_write :1; - /* Central_free is set if all free blocks are kept in the header. */ - unsigned central_free :1; + /* Central_free is set if all free blocks are kept in the header. */ + unsigned central_free :1; - /* Coalesce_blocks is set if we should try to merge free blocks. */ - unsigned coalesce_blocks :1; + /* Coalesce_blocks is set if we should try to merge free blocks. */ + unsigned coalesce_blocks :1; - /* Whether or not we should do file locking ourselves. */ - unsigned file_locking :1; + /* Whether or not we should do file locking ourselves. */ + unsigned file_locking :1; - /* Whether or not we're allowing mmap() use. */ - unsigned memory_mapping :1; + /* Whether or not we're allowing mmap() use. */ + unsigned memory_mapping :1; - /* Whether the database was open with GDBM_CLOEXEC flag */ - unsigned cloexec :1; + /* Whether the database was open with GDBM_CLOEXEC flag */ + unsigned cloexec :1; - /* Last error was fatal */ - unsigned fatal :1; + /* Last error was fatal, the database needs recovery */ + unsigned need_recovery :1; - /* Last error number */ - int last_error; + /* Last error number */ + int last_error; - /* Type of file locking in use. */ - enum { LOCKING_NONE = 0, LOCKING_FLOCK, LOCKING_LOCKF, - LOCKING_FCNTL } lock_type; + /* Type of file locking in use. */ + enum { LOCKING_NONE = 0, LOCKING_FLOCK, LOCKING_LOCKF, + LOCKING_FCNTL } lock_type; - /* The fatal error handling routine. */ - void (*fatal_err) (const char *); + /* The fatal error handling routine. */ + void (*fatal_err) (const char *); - /* The gdbm file descriptor which is set in gdbm_open. */ - int desc; + /* The gdbm file descriptor which is set in gdbm_open. */ + int desc; - /* The file header holds information about the database. */ - gdbm_file_header *header; - - /* The hash table directory from extendable hashing. See Fagin et al, - ACM Trans on Database Systems, Vol 4, No 3. Sept 1979, 315-344 */ - off_t *dir; - - /* The bucket cache. */ - cache_elem *bucket_cache; - size_t cache_size; - int last_read; - - /* Points to the current hash bucket in the cache. */ - hash_bucket *bucket; - - /* The directory entry used to get the current hash bucket. */ - int bucket_dir; - - /* Pointer to the current bucket's cache entry. */ - cache_elem *cache_entry; - - /* Bookkeeping of things that need to be written back at the - end of an update. */ - unsigned header_changed :1; - unsigned directory_changed :1; - unsigned bucket_changed :1; - unsigned second_changed :1; - - /* Mmap info */ - size_t mapped_size_max;/* Max. allowed value for mapped_size */ - void *mapped_region; /* Mapped region */ - size_t mapped_size; /* Size of the region */ - off_t mapped_pos; /* Current offset in the region */ - off_t mapped_off; /* Position in the file where the region - begins */ - }; + /* The file header holds information about the database. */ + gdbm_file_header *header; + + /* The hash table directory from extendable hashing. See Fagin et al, + ACM Trans on Database Systems, Vol 4, No 3. Sept 1979, 315-344 */ + off_t *dir; + + /* The bucket cache. */ + cache_elem *bucket_cache; + size_t cache_size; + int last_read; + + /* Points to the current hash bucket in the cache. */ + hash_bucket *bucket; + + /* The directory entry used to get the current hash bucket. */ + int bucket_dir; + + /* Pointer to the current bucket's cache entry. */ + cache_elem *cache_entry; + + /* Bookkeeping of things that need to be written back at the + end of an update. */ + unsigned header_changed :1; + unsigned directory_changed :1; + unsigned bucket_changed :1; + unsigned second_changed :1; + + /* Mmap info */ + size_t mapped_size_max;/* Max. allowed value for mapped_size */ + void *mapped_region; /* Mapped region */ + size_t mapped_size; /* Size of the region */ + off_t mapped_pos; /* Current offset in the region */ + off_t mapped_off; /* Position in the file where the region + begins */ +}; #define GDBM_DIR_COUNT(db) ((db)->header->dir_size / sizeof (off_t)) /* Execute CODE without clobbering errno */ -#define SAVE_ERRNO(code) \ - do \ - { \ - int __ec = errno; \ - code; \ - errno = __ec; \ - } \ - while (0) \ +#define SAVE_ERRNO(code) \ + do \ + { \ + int __ec = errno; \ + code; \ + errno = __ec; \ + } \ + while (0) \ #define _GDBM_MAX_DUMP_LINE_LEN 76 +/* Return immediately if the database needs recovery */ +#define GDBM_ASSERT_CONSISTENCY(dbf, onerr) \ + do \ + { \ + if (dbf->need_recovery) \ + { \ + gdbm_set_errno (dbf, GDBM_NEED_RECOVERY, 1); \ + return onerr; \ + } \ + } \ + while (0) + /* Now define all the routines in use. */ #include "proto.h" diff --git a/src/gdbmdelete.c b/src/gdbmdelete.c index 7e2867d..faa4957 100644 --- a/src/gdbmdelete.c +++ b/src/gdbmdelete.c @@ -36,13 +36,15 @@ gdbm_delete (GDBM_FILE dbf, datum key) off_t free_adr; /* Temporary storage for address and size. */ int free_size; + GDBM_ASSERT_CONSISTENCY (dbf, -1); + /* First check to make sure this guy is a writer. */ if (dbf->read_write == GDBM_READER) { gdbm_set_errno (dbf, GDBM_READER_CANT_DELETE, 0); return -1; } - + /* Initialize the gdbm_errno variable. */ gdbm_set_errno (dbf, GDBM_NO_ERROR, 0); diff --git a/src/gdbmdump.c b/src/gdbmdump.c index cf1e2fc..49f39bf 100644 --- a/src/gdbmdump.c +++ b/src/gdbmdump.c @@ -128,6 +128,9 @@ gdbm_dump_to_file (GDBM_FILE dbf, FILE *fp, int format) { int rc; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, -1); + switch (format) { case GDBM_DUMP_FMT_BINARY: @@ -159,6 +162,9 @@ gdbm_dump (GDBM_FILE dbf, const char *filename, int fmt, int open_flags, int nfd, rc; FILE *fp; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, -1); + /* Only support GDBM_WCREAT or GDBM_NEWDB */ switch (open_flags) { diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c index 2ff647f..4eeff8c 100644 --- a/src/gdbmerrno.c +++ b/src/gdbmerrno.c @@ -33,7 +33,7 @@ gdbm_set_errno (GDBM_FILE dbf, gdbm_error ec, int fatal) if (dbf) { dbf->last_error = ec; - dbf->fatal = fatal; + dbf->need_recovery = fatal; } gdbm_errno = ec; } @@ -91,6 +91,7 @@ const char * const gdbm_errlist[_GDBM_MAX_ERRNO+1] = { [GDBM_NO_DBNAME] = N_("Database name not given"), [GDBM_ERR_FILE_OWNER] = N_("Failed to restore file owner"), [GDBM_ERR_FILE_MODE] = N_("Failed to restore file mode"), + [GDBM_NEED_RECOVERY] = N_("Database needs recovery") }; const char * diff --git a/src/gdbmexists.c b/src/gdbmexists.c index 0d551c0..e44f04e 100644 --- a/src/gdbmexists.c +++ b/src/gdbmexists.c @@ -27,6 +27,9 @@ int gdbm_exists (GDBM_FILE dbf, datum key) { + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, 0); + if (_gdbm_findkey (dbf, key, NULL, NULL) < 0) { if (gdbm_errno == GDBM_ITEM_NOT_FOUND) diff --git a/src/gdbmexp.c b/src/gdbmexp.c index 613166e..f188040 100644 --- a/src/gdbmexp.c +++ b/src/gdbmexp.c @@ -32,6 +32,9 @@ gdbm_export_to_file (GDBM_FILE dbf, FILE *fp) const char *header2 = "\r\n!\r\n"; int count = 0; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, -1); + /* Write out the text header. */ if (fwrite (header1, strlen (header1), 1, fp) != 1) goto write_fail; diff --git a/src/gdbmfetch.c b/src/gdbmfetch.c index ca82550..25a6c1d 100644 --- a/src/gdbmfetch.c +++ b/src/gdbmfetch.c @@ -37,6 +37,9 @@ gdbm_fetch (GDBM_FILE dbf, datum key) return_val.dptr = NULL; return_val.dsize = 0; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, return_val); + /* Initialize the gdbm_errno variable. */ gdbm_set_errno (dbf, GDBM_NO_ERROR, 0); diff --git a/src/gdbmimp.c b/src/gdbmimp.c index 96c774f..6227a39 100644 --- a/src/gdbmimp.c +++ b/src/gdbmimp.c @@ -34,6 +34,9 @@ gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag) datum key, data; int count = 0; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, -1); + seenbang = 0; seennewline = 0; kbuffer = NULL; diff --git a/src/gdbmopen.c b/src/gdbmopen.c index b8b14e3..a45cb04 100644 --- a/src/gdbmopen.c +++ b/src/gdbmopen.c @@ -110,6 +110,9 @@ gdbm_open (const char *file, int block_size, int flags, int mode, dbf->file_locking = TRUE; /* Default to doing file locking. */ dbf->central_free = FALSE; /* Default to not using central_free. */ dbf->coalesce_blocks = FALSE; /* Default to not coalescing blocks. */ + + dbf->need_recovery = FALSE; + dbf->last_error = GDBM_NO_ERROR; /* GDBM_FAST used to determine whether or not we set fast_write. */ if (flags & GDBM_SYNC) diff --git a/src/gdbmreorg.c b/src/gdbmreorg.c index 360f5c8..8a0cc64 100644 --- a/src/gdbmreorg.c +++ b/src/gdbmreorg.c @@ -65,6 +65,8 @@ gdbm_reorganize (GDBM_FILE dbf) struct stat fileinfo; /* Information about the file. */ int index; /* Use in moving the bucket cache. */ + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, -1); /* Readers can not reorganize! */ if (dbf->read_write == GDBM_READER) diff --git a/src/gdbmseq.c b/src/gdbmseq.c index c62a13b..831339a 100644 --- a/src/gdbmseq.c +++ b/src/gdbmseq.c @@ -100,6 +100,9 @@ gdbm_firstkey (GDBM_FILE dbf) /* Set the default return value for not finding a first entry. */ return_val.dptr = NULL; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, return_val); + /* Initialize the gdbm_errno variable. */ gdbm_set_errno (dbf, GDBM_NO_ERROR, 0); @@ -121,12 +124,15 @@ gdbm_nextkey (GDBM_FILE dbf, datum key) datum return_val; /* The return value. */ int elem_loc; /* The location in the bucket. */ - /* Initialize the gdbm_errno variable. */ - gdbm_set_errno (dbf, GDBM_NO_ERROR, 0); - /* Set the default return value for no next entry. */ return_val.dptr = NULL; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, return_val); + + /* Initialize the gdbm_errno variable. */ + gdbm_set_errno (dbf, GDBM_NO_ERROR, 0); + /* Do we have a valid key? */ if (key.dptr == NULL) { diff --git a/src/gdbmsetopt.c b/src/gdbmsetopt.c index e372a92..47e01ad 100644 --- a/src/gdbmsetopt.c +++ b/src/gdbmsetopt.c @@ -57,6 +57,9 @@ gdbm_setopt (GDBM_FILE dbf, int optflag, void *optval, int optlen) int n; size_t sz; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, -1); + switch (optflag) { /* Cache size: */ diff --git a/src/gdbmstore.c b/src/gdbmstore.c index f166ba9..ec4b96b 100644 --- a/src/gdbmstore.c +++ b/src/gdbmstore.c @@ -47,6 +47,9 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) int new_size; /* Used in allocating space. */ int rc; + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, -1); + /* First check to make sure this guy is a writer. */ if (dbf->read_write == GDBM_READER) { @@ -99,7 +102,7 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) } } else if (gdbm_errno == GDBM_ITEM_NOT_FOUND) - gdbm_set_errno (dbf, GDBM_NO_ERROR, 0); //clear error state + gdbm_set_errno (dbf, GDBM_NO_ERROR, 0); /* clear error state */ else return -1; diff --git a/src/gdbmsync.c b/src/gdbmsync.c index c9b146c..1d2a1d4 100644 --- a/src/gdbmsync.c +++ b/src/gdbmsync.c @@ -27,6 +27,8 @@ void gdbm_sync (GDBM_FILE dbf) { + /* Return immediately if the database needs recovery */ + GDBM_ASSERT_CONSISTENCY (dbf, ); /* Initialize the gdbm_errno variable. */ gdbm_set_errno (dbf, GDBM_NO_ERROR, 0); |