diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-07-09 11:40:19 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-07-09 12:11:20 +0300 |
commit | e8cad816f36b1cad11bb67c96f0ce878cf30844e (patch) | |
tree | c971d9de6369f9e340a3764d848c24d4a2ce96e8 | |
parent | 0eafbb93c82a489204f54259593f2aaeb9cdbfc4 (diff) | |
download | gdbm-e8cad816f36b1cad11bb67c96f0ce878cf30844e.tar.gz gdbm-e8cad816f36b1cad11bb67c96f0ce878cf30844e.tar.bz2 |
Don't bail out on fatal errors, unless the user defines the fatal_err function
* src/bucket.c (_gdbm_get_bucket)
(_gdbm_split_bucket, _gdbm_write_bucket): Return error code. All callers
updated.
* src/proto.h (_gdbm_get_bucket)
(_gdbm_split_bucket, _gdbm_write_bucket): Update declarations
* src/falloc.c (push_avail_block)
(pop_avail_block): Return error code. All callers
updated.
* src/update.c (_gdbm_fatal): Exit only if the user defined
fatal_err function.
* src/gdbmerrno.c (gdbm_needs_recovery): New function.
* src/gdbm.h.in (gdbm_needs_recovery): New proto.
* compat/dbminit.c: Set gdbm_errno on fatal errors.
* compat/dbmopen.c: Likewise.
* src/findkey.c: Likewise.
* src/gdbm_load.c: Likewise.
* src/gdbmcount.c: Likewise.
* src/gdbmdefs.h: Likewise.
* src/gdbmdelete.c: Likewise.
* src/gdbmdump.c: Likewise.
* src/gdbmexists.c: Likewise.
* src/gdbmexp.c: Likewise.
* src/gdbmfetch.c: Likewise.
* src/gdbmimp.c: Likewise.
* src/gdbmload.c: Likewise.
* src/gdbmopen.c: Likewise.
* src/gdbmreorg.c: Likewise.
* src/gdbmseq.c: Likewise.
* src/gdbmsetopt.c: Likewise.
* src/gdbmstore.c: Likewise.
* src/gdbmsync.c: Likewise.
* src/mmap.c: Likewise.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | compat/dbminit.c | 2 | ||||
-rw-r--r-- | compat/dbmopen.c | 24 | ||||
-rw-r--r-- | src/bucket.c | 89 | ||||
-rw-r--r-- | src/falloc.c | 81 | ||||
-rw-r--r-- | src/findkey.c | 30 | ||||
-rw-r--r-- | src/gdbm.h.in | 1 | ||||
-rw-r--r-- | src/gdbm_load.c | 4 | ||||
-rw-r--r-- | src/gdbmcount.c | 2 | ||||
-rw-r--r-- | src/gdbmdefs.h | 2 | ||||
-rw-r--r-- | src/gdbmdelete.c | 7 | ||||
-rw-r--r-- | src/gdbmdump.c | 14 | ||||
-rw-r--r-- | src/gdbmerrno.c | 8 | ||||
-rw-r--r-- | src/gdbmexists.c | 2 | ||||
-rw-r--r-- | src/gdbmexp.c | 12 | ||||
-rw-r--r-- | src/gdbmfetch.c | 4 | ||||
-rw-r--r-- | src/gdbmimp.c | 10 | ||||
-rw-r--r-- | src/gdbmload.c | 12 | ||||
-rw-r--r-- | src/gdbmopen.c | 48 | ||||
-rw-r--r-- | src/gdbmreorg.c | 26 | ||||
-rw-r--r-- | src/gdbmseq.c | 21 | ||||
-rw-r--r-- | src/gdbmsetopt.c | 40 | ||||
-rw-r--r-- | src/gdbmstore.c | 43 | ||||
-rw-r--r-- | src/gdbmsync.c | 2 | ||||
-rw-r--r-- | src/mmap.c | 6 | ||||
-rw-r--r-- | src/proto.h | 8 | ||||
-rw-r--r-- | src/update.c | 69 |
27 files changed, 363 insertions, 206 deletions
@@ -26,12 +26,14 @@ Instead it sets gdbm_errno to GDBM_MALLOC_ERROR and returns NULL datum. * New functions ** gdbm_last_errno ** gdbm_clear_error +** gdbm_needs_recovery + Version 1.12, 2016-05-16 * New configuration variable COMPATINCLUDEDIR When used with --enable-libgdbm-compat, this variable points to the diff --git a/compat/dbminit.c b/compat/dbminit.c index f5203d1..526410d 100644 --- a/compat/dbminit.c +++ b/compat/dbminit.c @@ -45,12 +45,12 @@ dbminit (char *file) if (_gdbm_file == NULL) { _gdbm_file = dbm_open (file, O_RDONLY, 0644); /* Did we successfully open the file? */ if (_gdbm_file == NULL) { - gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, 1); + gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, TRUE); return -1; } } return 0; } diff --git a/compat/dbmopen.c b/compat/dbmopen.c index af423df..f576b37 100644 --- a/compat/dbmopen.c +++ b/compat/dbmopen.c @@ -68,13 +68,13 @@ ndbm_open_dir_file0 (const char *file_name, int pagfd, int mode) if (mode & GDBM_CLOEXEC) flags |= O_CLOEXEC; if (fstat (pagfd, &pagst)) { - gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, 1); /* FIXME: special code? */ + gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, TRUE); /* FIXME: special code? */ return -1; } /* Previous versions of GDBM linked pag to dir. Try to detect this: */ if (stat (file_name, &st) == 0) { @@ -86,42 +86,42 @@ ndbm_open_dir_file0 (const char *file_name, int pagfd, int mode) { if ((mode & GDBM_OPENMASK) == GDBM_READER) /* Ok, try to cope with it. */ return pagfd; else { - gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, 1); + gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, TRUE); return -1; } } } else { - gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, 1); + gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, FALSE); return -1; } } else if (st.st_size == 0) /* ok */; else if (st.st_size != DEF_DIR_SIZE) { - gdbm_set_errno (NULL, GDBM_BAD_MAGIC_NUMBER, 1); + gdbm_set_errno (NULL, GDBM_BAD_MAGIC_NUMBER, FALSE); return -1; } else { fd = open (file_name, flags); if (fd == -1) { - gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, 1); + gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, FALSE); return fd; } if (read (fd, dirbuf, sizeof (dirbuf)) != sizeof (dirbuf)) { - gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, 1); + gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, FALSE); close (fd); return -1; } if (getint (dirbuf) == GDBM_DIR_MAGIC) { @@ -132,13 +132,13 @@ ndbm_open_dir_file0 (const char *file_name, int pagfd, int mode) v[2] = getint (dirbuf + 12); if (gdbm_version_cmp (v, gdbm_version_number) <= 0) return fd; } close (fd); - gdbm_set_errno (NULL, GDBM_BAD_MAGIC_NUMBER, 1); + gdbm_set_errno (NULL, GDBM_BAD_MAGIC_NUMBER, FALSE); return -1; } } /* File does not exist. Create it. */ fd = open (file_name, flags | O_CREAT, pagst.st_mode & 0777); @@ -148,13 +148,13 @@ ndbm_open_dir_file0 (const char *file_name, int pagfd, int mode) putint (dirbuf + 4, gdbm_version_number[0]); putint (dirbuf + 8, gdbm_version_number[1]); putint (dirbuf + 12, gdbm_version_number[2]); if (write (fd, dirbuf, sizeof (dirbuf)) != sizeof (dirbuf)) { - gdbm_set_errno (NULL, GDBM_FILE_WRITE_ERROR, 1); + gdbm_set_errno (NULL, GDBM_FILE_WRITE_ERROR, FALSE); close (fd); fd = -1; } } return fd; @@ -165,13 +165,13 @@ ndbm_open_dir_file (const char *base, int pagfd, int mode) { char *file_name = malloc (strlen (base) + sizeof (DIRSUF)); int fd; if (!file_name) { - gdbm_set_errno (NULL, GDBM_MALLOC_ERROR, 1); + gdbm_set_errno (NULL, GDBM_MALLOC_ERROR, FALSE); return -1; } fd = ndbm_open_dir_file0 (strcat (strcpy (file_name, base), DIRSUF), pagfd, mode); free (file_name); return fd; @@ -209,13 +209,13 @@ dbm_open (char *file, int flags, int mode) int f; /* Prepare the correct name for "file.pag". */ pag_file = (char *) malloc (strlen (file) + 5); if (!pag_file) { - gdbm_set_errno (NULL, GDBM_MALLOC_ERROR, 1); /* For the hell of it. */ + gdbm_set_errno (NULL, GDBM_MALLOC_ERROR, FALSE); /* For the hell of it. */ return NULL; } strcpy (pag_file, file); strcat (pag_file, ".pag"); @@ -247,22 +247,22 @@ dbm_open (char *file, int flags, int mode) open_flags |= GDBM_NOLOCK; dbm = calloc (1, sizeof (*dbm)); if (!dbm) { free (pag_file); - gdbm_set_errno (NULL, GDBM_MALLOC_ERROR, 1); /* For the hell of it. */ + gdbm_set_errno (NULL, GDBM_MALLOC_ERROR, FALSE); /* For the hell of it. */ return NULL; } dbm->file = gdbm_open (pag_file, 0, open_flags, mode, NULL); /* Did we successfully open the file? */ if (dbm->file == NULL) { - gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, 1); + gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, FALSE); free (dbm); dbm = NULL; } else { dbm->dirfd = ndbm_open_dir_file (file, dbm->file->desc, open_flags); diff --git a/src/bucket.c b/src/bucket.c index ee0e157..96ed8b4 100644 --- a/src/bucket.c +++ b/src/bucket.c @@ -46,13 +46,13 @@ _gdbm_new_bucket (GDBM_FILE dbf, hash_bucket *bucket, int bits) /* Find a bucket for DBF that is pointed to by the bucket directory from location DIR_INDEX. The bucket cache is first checked to see if it is already in memory. If not, a bucket may be tossed to read the new bucket. In any case, the requested bucket becomes the "current" bucket and dbf->bucket points to the correct bucket. */ -void +int _gdbm_get_bucket (GDBM_FILE dbf, int dir_index) { int rc; off_t bucket_adr; /* The address of the correct hash bucket. */ off_t file_pos; /* The return address for lseek. */ int index; /* Loop index. */ @@ -60,51 +60,65 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index) /* Initial set up. */ dbf->bucket_dir = dir_index; bucket_adr = dbf->dir [dir_index]; if (dbf->bucket_cache == NULL) { - if(_gdbm_init_cache(dbf, DEFAULT_CACHESIZE) == -1) - _gdbm_fatal(dbf, _("couldn't init cache")); + if (_gdbm_init_cache (dbf, DEFAULT_CACHESIZE) == -1) + { + _gdbm_fatal (dbf, _("couldn't init cache")); + return -1; + } } /* Is that one is not already current, we must find it. */ if (dbf->cache_entry->ca_adr != bucket_adr) { /* Look in the cache. */ for (index = 0; index < dbf->cache_size; index++) { if (dbf->bucket_cache[index].ca_adr == bucket_adr) { dbf->bucket = dbf->bucket_cache[index].ca_bucket; dbf->cache_entry = &dbf->bucket_cache[index]; - return; + return 0; } } /* It is not in the cache, read it from the disk. */ dbf->last_read = (dbf->last_read + 1) % dbf->cache_size; if (dbf->bucket_cache[dbf->last_read].ca_changed) - _gdbm_write_bucket (dbf, &dbf->bucket_cache[dbf->last_read]); + { + if (_gdbm_write_bucket (dbf, &dbf->bucket_cache[dbf->last_read])) + return -1; + } dbf->bucket_cache[dbf->last_read].ca_adr = bucket_adr; dbf->bucket = dbf->bucket_cache[dbf->last_read].ca_bucket; dbf->cache_entry = &dbf->bucket_cache[dbf->last_read]; dbf->cache_entry->ca_data.elem_loc = -1; dbf->cache_entry->ca_changed = FALSE; /* Read the bucket. */ file_pos = __lseek (dbf, bucket_adr, SEEK_SET); if (file_pos != bucket_adr) - _gdbm_fatal (dbf, _("lseek error")); + { + _gdbm_fatal (dbf, _("lseek error")); + gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE); + return -1; + } rc = _gdbm_full_read (dbf, dbf->bucket, dbf->header->bucket_size); if (rc) - _gdbm_fatal (dbf, gdbm_strerror (rc)); + { + _gdbm_fatal (dbf, gdbm_strerror (rc)); + gdbm_set_errno (dbf, rc, TRUE); + return -1; + } } - return; + return 0; } int _gdbm_read_bucket_at (GDBM_FILE dbf, off_t off, hash_bucket *bucket, size_t size) { @@ -128,29 +142,29 @@ _gdbm_read_bucket_at (GDBM_FILE dbf, off_t off, hash_bucket *bucket, } /* Read the bucket. */ file_pos = __lseek (dbf, off, SEEK_SET); if (file_pos != off) { - gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, 1); + gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE); return -1; } rc = _gdbm_full_read (dbf, bucket, size); if (rc) { - gdbm_set_errno (dbf, rc, 1); + gdbm_set_errno (dbf, rc, TRUE); return -1; } return 0; } /* Split the current bucket. This includes moving all items in the bucket to a new bucket. This doesn't require any disk reads because all hash values are stored in the buckets. Splitting the current bucket may require doubling the size of the hash directory. */ -void +int _gdbm_split_bucket (GDBM_FILE dbf, int next_insert) { hash_bucket *bucket[2]; /* Pointers to the new buckets. */ int new_bits; /* The number of bits for the new buckets. */ int cache_0; /* Location in the cache for the buckets. */ @@ -173,20 +187,22 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert) int index; /* Used in array indexing. */ int index1; /* Used in array indexing. */ int elem_loc; /* Location in new bucket to put element. */ bucket_element *old_el; /* Pointer into the old bucket. */ int select; /* Used to index bucket during movement. */ - /* No directories are yet old. */ old_count = 0; if (dbf->bucket_cache == NULL) { - if(_gdbm_init_cache(dbf, DEFAULT_CACHESIZE) == -1) - _gdbm_fatal(dbf, _("couldn't init cache")); + if (_gdbm_init_cache(dbf, DEFAULT_CACHESIZE) == -1) + { + _gdbm_fatal (dbf, _("couldn't init cache")); + return -1; + } } while (dbf->bucket->count == dbf->header->bucket_elems) { /* Initialize the "new" buckets in the cache. */ do @@ -194,37 +210,55 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert) dbf->last_read = (dbf->last_read + 1) % dbf->cache_size; cache_0 = dbf->last_read; } while (dbf->bucket_cache[cache_0].ca_bucket == dbf->bucket); bucket[0] = dbf->bucket_cache[cache_0].ca_bucket; if (dbf->bucket_cache[cache_0].ca_changed) - _gdbm_write_bucket (dbf, &dbf->bucket_cache[cache_0]); + { + if (_gdbm_write_bucket (dbf, &dbf->bucket_cache[cache_0])) + return -1; + } do { dbf->last_read = (dbf->last_read + 1) % dbf->cache_size; cache_1 = dbf->last_read; } while (dbf->bucket_cache[cache_1].ca_bucket == dbf->bucket); bucket[1] = dbf->bucket_cache[cache_1].ca_bucket; if (dbf->bucket_cache[cache_1].ca_changed) - _gdbm_write_bucket (dbf, &dbf->bucket_cache[cache_1]); + { + if (_gdbm_write_bucket (dbf, &dbf->bucket_cache[cache_1])) + return -1; + } new_bits = dbf->bucket->bucket_bits+1; _gdbm_new_bucket (dbf, bucket[0], new_bits); _gdbm_new_bucket (dbf, bucket[1], new_bits); - adr_0 = _gdbm_alloc (dbf, dbf->header->bucket_size); + adr_0 = _gdbm_alloc (dbf, dbf->header->bucket_size); + if (adr_0 == 0) + return -1; dbf->bucket_cache[cache_0].ca_adr = adr_0; adr_1 = _gdbm_alloc (dbf, dbf->header->bucket_size); + if (adr_1 == 0) + return -1; dbf->bucket_cache[cache_1].ca_adr = adr_1; /* Double the directory size if necessary. */ if (dbf->header->dir_bits == dbf->bucket->bucket_bits) { dir_size = dbf->header->dir_size * 2; dir_adr = _gdbm_alloc (dbf, dir_size); + if (dir_adr == 0) + return -1; new_dir = (off_t *) malloc (dir_size); - if (new_dir == NULL) _gdbm_fatal (dbf, _("malloc error")); + if (new_dir == NULL) + { + gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, TRUE); + _gdbm_fatal (dbf, _("malloc error")); + return -1; + } + for (index = 0; index < GDBM_DIR_COUNT (dbf); index++) { new_dir[2*index] = dbf->dir[index]; new_dir[2*index+1] = dbf->dir[index]; } @@ -255,12 +289,14 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert) bucket[select]->count += 1; } /* Allocate avail space for the bucket[1]. */ bucket[1]->bucket_avail[0].av_adr = _gdbm_alloc (dbf, dbf->header->block_size); + if (bucket[1]->bucket_avail[0].av_adr == 0) + return -1; bucket[1]->bucket_avail[0].av_size = dbf->header->block_size; bucket[1]->av_count = 1; /* Copy the avail elements in dbf->bucket to bucket[0]. */ bucket[0]->av_count = dbf->bucket->av_count; index = 0; @@ -326,29 +362,40 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert) } /* Get rid of old directories. */ for (index = 0; index < old_count; index++) _gdbm_free (dbf, old_adr[index], old_size[index]); + + return 0; } /* The only place where a bucket is written. CA_ENTRY is the cache entry containing the bucket to be written. */ -void +int _gdbm_write_bucket (GDBM_FILE dbf, cache_elem *ca_entry) { int rc; off_t file_pos; /* The return value for lseek. */ file_pos = __lseek (dbf, ca_entry->ca_adr, SEEK_SET); if (file_pos != ca_entry->ca_adr) - _gdbm_fatal (dbf, _("lseek error")); + { + gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE); + _gdbm_fatal (dbf, _("lseek error")); + return -1; + } rc = _gdbm_full_write (dbf, ca_entry->ca_bucket, dbf->header->bucket_size); if (rc) - _gdbm_fatal (dbf, gdbm_strerror (rc)); + { + gdbm_set_errno (dbf, rc, TRUE); + _gdbm_fatal (dbf, gdbm_strerror (rc)); + return -1; + } ca_entry->ca_changed = FALSE; ca_entry->ca_data.hash_val = -1; ca_entry->ca_data.elem_loc = -1; + return 0; } diff --git a/src/falloc.c b/src/falloc.c index 32aad51..58a9431 100644 --- a/src/falloc.c +++ b/src/falloc.c @@ -25,14 +25,14 @@ /* The forward definitions for this file. See the functions for the definition of the function. */ static avail_elem get_elem (int, avail_elem [], int *); static avail_elem get_block (int, GDBM_FILE); -static void push_avail_block (GDBM_FILE); -static void pop_avail_block (GDBM_FILE); +static int push_avail_block (GDBM_FILE); +static int pop_avail_block (GDBM_FILE); static void adjust_bucket_avail (GDBM_FILE); /* Allocate space in the file DBF for a block NUM_BYTES in length. Return the file address of the start of the block. Each hash bucket has a fixed size avail table. We first check this @@ -62,13 +62,14 @@ _gdbm_alloc (GDBM_FILE dbf, int num_bytes) if (av_el.av_size == 0) { /* If the header avail table is less than half full, and there's something on the stack. */ if ((dbf->header->avail.count <= (dbf->header->avail.size >> 1)) && (dbf->header->avail.next_block != 0)) - pop_avail_block (dbf); + if (pop_avail_block (dbf)) + return 0; /* check the header avail table next */ av_el = get_elem (num_bytes, dbf->header->avail.av_table, &dbf->header->avail.count); if (av_el.av_size == 0) /* Get another full block from end of file. */ @@ -111,13 +112,13 @@ _gdbm_free (GDBM_FILE dbf, off_t file_adr, int num_bytes) /* Is the freed space large or small? */ if ((num_bytes >= dbf->header->block_size) || dbf->central_free) { if (dbf->header->avail.count == dbf->header->avail.size) { - push_avail_block (dbf); + push_avail_block (dbf);//FIXME: return } _gdbm_put_av_elem (temp, dbf->header->avail.av_table, &dbf->header->avail.count, dbf->coalesce_blocks); dbf->header_changed = TRUE; } else @@ -127,13 +128,13 @@ _gdbm_free (GDBM_FILE dbf, off_t file_adr, int num_bytes) _gdbm_put_av_elem (temp, dbf->bucket->bucket_avail, &dbf->bucket->av_count, dbf->coalesce_blocks); else { if (dbf->header->avail.count == dbf->header->avail.size) { - push_avail_block (dbf); + push_avail_block (dbf); //FIXME: return } _gdbm_put_av_elem (temp, dbf->header->avail.av_table, &dbf->header->avail.count, dbf->coalesce_blocks); dbf->header_changed = TRUE; } } @@ -152,62 +153,79 @@ _gdbm_free (GDBM_FILE dbf, off_t file_adr, int num_bytes) /* Gets the avail block at the top of the stack and loads it into the active avail block. It does a "free" for itself! This can (and is) now called even when the avail block is not empty, so we must be smart about things. */ -static void +static int pop_avail_block (GDBM_FILE dbf) { int rc; off_t file_pos; /* For use with the lseek system call. */ avail_elem new_el; avail_block *new_blk; int index; if (dbf->header->avail.count == dbf->header->avail.size) { /* We're kind of stuck here, so we re-split the header in order to avoid crashing. Sigh. */ - push_avail_block(dbf); + if (push_avail_block (dbf)) + return -1; } /* Set up variables. */ new_el.av_adr = dbf->header->avail.next_block; new_el.av_size = ( ( (dbf->header->avail.size * sizeof (avail_elem)) >> 1) + sizeof (avail_block)); /* Allocate space for the block. */ new_blk = (avail_block *) malloc (new_el.av_size); - if (new_blk == NULL) _gdbm_fatal(dbf, _("malloc failed")); + if (new_blk == NULL) + { + gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, TRUE); + _gdbm_fatal(dbf, _("malloc failed")); + return -1; + } /* Read the block. */ file_pos = __lseek (dbf, new_el.av_adr, SEEK_SET); - if (file_pos != new_el.av_adr) _gdbm_fatal (dbf, _("lseek error")); + if (file_pos != new_el.av_adr) + { + gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE); + _gdbm_fatal (dbf, _("lseek error")); + return -1; + } + rc = _gdbm_full_read (dbf, new_blk, new_el.av_size); if (rc) - _gdbm_fatal (dbf, gdbm_strerror (rc)); + { + gdbm_set_errno (dbf, rc, TRUE); + _gdbm_fatal (dbf, gdbm_strerror (rc)); + return -1; + } /* Add the elements from the new block to the header. */ index = 0; while (index < new_blk->count) { while(index < new_blk->count && dbf->header->avail.count < dbf->header->avail.size) { /* With luck, this will merge a lot of blocks! */ - _gdbm_put_av_elem(new_blk->av_table[index], - dbf->header->avail.av_table, - &dbf->header->avail.count, TRUE); + _gdbm_put_av_elem (new_blk->av_table[index], + dbf->header->avail.av_table, + &dbf->header->avail.count, TRUE); index++; } if (dbf->header->avail.count == dbf->header->avail.size) { /* We're kind of stuck here, so we re-split the header in order to avoid crashing. Sigh. */ - push_avail_block(dbf); + if (push_avail_block (dbf)) + return -1; } } /* Fix next_block, as well. */ dbf->header->avail.next_block = new_blk->next_block; @@ -217,24 +235,27 @@ pop_avail_block (GDBM_FILE dbf) /* Free the previous avail block. It is possible that the header table is now FULL, which will cause us to overflow it! */ if (dbf->header->avail.count == dbf->header->avail.size) { /* We're kind of stuck here, so we re-split the header in order to avoid crashing. Sigh. */ - push_avail_block(dbf); + if (push_avail_block (dbf)) + return -1; } _gdbm_put_av_elem (new_el, dbf->header->avail.av_table, &dbf->header->avail.count, TRUE); free (new_blk); + + return 0; } /* Splits the header avail block and pushes half onto the avail stack. */ -static void +static int push_avail_block (GDBM_FILE dbf) { int av_size; off_t av_adr; int index; off_t file_pos; @@ -250,16 +271,21 @@ push_avail_block (GDBM_FILE dbf) new_loc = get_elem (av_size, dbf->header->avail.av_table, &dbf->header->avail.count); if (new_loc.av_size == 0) new_loc = get_block (av_size, dbf); av_adr = new_loc.av_adr; - /* Split the header block. */ temp = (avail_block *) malloc (av_size); - if (temp == NULL) _gdbm_fatal (dbf, _("malloc error")); + if (temp == NULL) + { + gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, TRUE); + _gdbm_fatal (dbf, _("malloc error")); + return -1; + } + /* Set the size to be correct AFTER the pop_avail_block. */ temp->size = dbf->header->avail.size; temp->count = 0; temp->next_block = dbf->header->avail.next_block; dbf->header->avail.next_block = av_adr; for (index = 1; index < dbf->header->avail.count; index++) @@ -276,20 +302,31 @@ push_avail_block (GDBM_FILE dbf) new_loc.av_adr += av_size; new_loc.av_size -= av_size; _gdbm_free (dbf, new_loc.av_adr, new_loc.av_size); /* Update the disk. */ file_pos = __lseek (dbf, av_adr, SEEK_SET); - if (file_pos != av_adr) _gdbm_fatal (dbf, _("lseek error")); + if (file_pos != av_adr) + { + gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE); + _gdbm_fatal (dbf, _("lseek error")); + return -1; + } + rc = _gdbm_full_write (dbf, temp, av_size); if (rc) - _gdbm_fatal (dbf, gdbm_strerror (rc)); - free (temp); -} + { + gdbm_set_errno (dbf, rc, TRUE); + _gdbm_fatal (dbf, gdbm_strerror (rc)); + return -1; + } + free (temp); + return 0; +} /* Get_elem returns an element in the AV_TABLE block which is larger than SIZE. AV_COUNT is the number of elements in the AV_TABLE. If an item is found, it extracts it from the AV_TABLE and moves the other elements up to fill the space. If no block is found larger than SIZE, get_elem returns a size of zero. This diff --git a/src/findkey.c b/src/findkey.c index 6b13fbf..34091e1 100644 --- a/src/findkey.c +++ b/src/findkey.c @@ -51,23 +51,36 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc) data_ca->elem_loc = elem_loc; data_ca->hash_val = dbf->bucket->h_table[elem_loc].hash_value; if (key_size+data_size == 0) data_ca->dptr = (char *) malloc (1); else data_ca->dptr = (char *) malloc (key_size+data_size); - if (data_ca->dptr == NULL) _gdbm_fatal (dbf, _("malloc error")); - + if (data_ca->dptr == NULL) + { + gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, FALSE); + _gdbm_fatal (dbf, _("malloc error")); + return NULL; + } /* Read into the cache. */ file_pos = __lseek (dbf, dbf->bucket->h_table[elem_loc].data_pointer, SEEK_SET); if (file_pos != dbf->bucket->h_table[elem_loc].data_pointer) - _gdbm_fatal (dbf, _("lseek error")); + { + gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE); + _gdbm_fatal (dbf, _("lseek error")); + return NULL; + } + rc = _gdbm_full_read (dbf, data_ca->dptr, key_size+data_size); if (rc) - _gdbm_fatal (dbf, gdbm_strerror (rc)); + { + gdbm_set_errno (dbf, rc, TRUE); + _gdbm_fatal (dbf, gdbm_strerror (rc)); + return NULL; + } return data_ca->dptr; } /* Find the KEY in the file and get ready to read the associated data. The return value is the location in the current hash bucket of the KEY's @@ -89,14 +102,15 @@ _gdbm_findkey (GDBM_FILE dbf, datum key, char **ret_dptr, int *ret_hash_val) int key_size; /* Size of the key on the file. */ /* Compute hash value and load proper bucket. */ new_hash_val = _gdbm_hash (key); if (ret_hash_val) *ret_hash_val = new_hash_val; - _gdbm_get_bucket (dbf, new_hash_val>> (31-dbf->header->dir_bits)); - + if (_gdbm_get_bucket (dbf, new_hash_val >> (31 - dbf->header->dir_bits))) + return -1; + /* Is the element the last one found for this bucket? */ if (dbf->cache_entry->ca_data.elem_loc != -1 && new_hash_val == dbf->cache_entry->ca_data.hash_val && dbf->cache_entry->ca_data.key_size == key.dsize && dbf->cache_entry->ca_data.dptr != NULL && memcmp (dbf->cache_entry->ca_data.dptr, key.dptr, key.dsize) == 0) @@ -127,12 +141,14 @@ _gdbm_findkey (GDBM_FILE dbf, datum key, char **ret_dptr, int *ret_hash_val) } else { /* This may be the one we want. The only way to tell is to read it. */ file_key = _gdbm_read_entry (dbf, elem_loc); + if (!file_key) + return -1; if (memcmp (file_key, key.dptr, key_size) == 0) { /* This is the item. */ if (ret_dptr) *ret_dptr = file_key + key.dsize; return elem_loc; @@ -146,10 +162,10 @@ _gdbm_findkey (GDBM_FILE dbf, datum key, char **ret_dptr, int *ret_hash_val) bucket_hash_val = dbf->bucket->h_table[elem_loc].hash_value; } } } /* If we get here, we never found the key. */ - gdbm_set_errno (dbf, GDBM_ITEM_NOT_FOUND, 0); + gdbm_set_errno (dbf, GDBM_ITEM_NOT_FOUND, FALSE); return -1; } diff --git a/src/gdbm.h.in b/src/gdbm.h.in index 83f99c2..a3d0461 100644 --- a/src/gdbm.h.in +++ b/src/gdbm.h.in @@ -180,12 +180,13 @@ typedef int gdbm_error; /* For compatibilities sake. */ extern gdbm_error gdbm_errno; extern const char * const gdbm_errlist[]; extern int gdbm_last_errno (GDBM_FILE dbf); extern void gdbm_set_errno (GDBM_FILE dbf, gdbm_error ec, int fatal); extern void gdbm_clear_error (GDBM_FILE dbf); +extern int gdbm_needs_recovery (GDBM_FILE dbf); /* extra prototypes */ extern const char *gdbm_strerror (gdbm_error); extern int gdbm_version_cmp (int const a[], int const b[]); diff --git a/src/gdbm_load.c b/src/gdbm_load.c index fd404b9..c4b9ee6 100644 --- a/src/gdbm_load.c +++ b/src/gdbm_load.c @@ -50,19 +50,19 @@ set_meta_info (GDBM_FILE dbf) int fd = gdbm_fdesc (dbf); if (meta_mask & GDBM_META_MASK_OWNER) { if (fchown (fd, owner_uid, owner_gid)) { - gdbm_set_errno (dbf, GDBM_ERR_FILE_OWNER, 0); + gdbm_set_errno (dbf, GDBM_ERR_FILE_OWNER, FALSE); return 1; } } if ((meta_mask & GDBM_META_MASK_MODE) && fchmod (fd, mode)) { - gdbm_set_errno (dbf, GDBM_ERR_FILE_OWNER, 0); + gdbm_set_errno (dbf, GDBM_ERR_FILE_OWNER, FALSE); return 1; } } return 0; } diff --git a/src/gdbmcount.c b/src/gdbmcount.c index 472f0d3..a301d0c 100644 --- a/src/gdbmcount.c +++ b/src/gdbmcount.c @@ -43,13 +43,13 @@ gdbm_count (GDBM_FILE dbf, gdbm_count_t *pcount) /* Return immediately if the database needs recovery */ GDBM_ASSERT_CONSISTENCY (dbf, -1); sdir = malloc (dbf->header->dir_size); if (!sdir) { - gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, 0); + gdbm_set_errno (dbf, GDBM_MALLOC_ERRO |