aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2016-07-09 11:40:19 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2016-07-09 12:11:20 +0300
commite8cad816f36b1cad11bb67c96f0ce878cf30844e (patch)
treec971d9de6369f9e340a3764d848c24d4a2ce96e8
parent0eafbb93c82a489204f54259593f2aaeb9cdbfc4 (diff)
downloadgdbm-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--NEWS2
-rw-r--r--compat/dbminit.c2
-rw-r--r--compat/dbmopen.c24
-rw-r--r--src/bucket.c89
-rw-r--r--src/falloc.c81
-rw-r--r--src/findkey.c30
-rw-r--r--src/gdbm.h.in1
-rw-r--r--src/gdbm_load.c4
-rw-r--r--src/gdbmcount.c2
-rw-r--r--src/gdbmdefs.h2
-rw-r--r--src/gdbmdelete.c7
-rw-r--r--src/gdbmdump.c14
-rw-r--r--src/gdbmerrno.c8
-rw-r--r--src/gdbmexists.c2
-rw-r--r--src/gdbmexp.c12
-rw-r--r--src/gdbmfetch.c4
-rw-r--r--src/gdbmimp.c10
-rw-r--r--src/gdbmload.c12
-rw-r--r--src/gdbmopen.c48
-rw-r--r--src/gdbmreorg.c26
-rw-r--r--src/gdbmseq.c21
-rw-r--r--src/gdbmsetopt.c40
-rw-r--r--src/gdbmstore.c43
-rw-r--r--src/gdbmsync.c2
-rw-r--r--src/mmap.c6
-rw-r--r--src/proto.h8
-rw-r--r--src/update.c69
27 files changed, 363 insertions, 206 deletions
diff --git a/NEWS b/NEWS
index 4efabdb..a564b2e 100644
--- a/NEWS
+++ b/NEWS
@@ -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