aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2016-07-20 14:40:08 +0300
committerSergey Poznyakoff <gray@gnu.org>2016-07-20 14:50:21 +0300
commitde7834e96602695db1cb6efd6238398b84d2ca60 (patch)
tree2fc49853a76d68a8db11aab24017843102fd22a8 /src
parentfbb0df69ca498a4fb4689a6d12c2f05e2cfaf175 (diff)
downloadgdbm-de7834e96602695db1cb6efd6238398b84d2ca60.tar.gz
gdbm-de7834e96602695db1cb6efd6238398b84d2ca60.tar.bz2
Introduce debug hooks.
* configure.ac: New option --enable-debug Print feature summary at the end of the run. * src/debug.c: New file. * src/Makefile.am [GDBM_COND_DEBUG_ENABLE]: Build debug.o Define GDBM_DEBUG_ENABLE. * src/gdbmdefs.h [GDBM_DEBUG_ENABLE] (_gdbm_debug_hook_install) (_gdbm_debug_hook_remove,_gdbm_debug_hook_check) (_gdbm_debug_hook_val): New protos. (GDBM_DEBUG_HOOK, GDBM_DEBUG_OVERRIDE) (GDBM_DEBUG_ALLOC): New defines. * src/gdbm.h.in (GDBM_RCVR_FORCE): New flag. * src/recover.c (gdbm_recover): Check database before attempting recovery, unless GDBM_RCVR_FORCE flag is set. * doc/gdbm.texi: Document GDBM_RCVR_FORCE * src/gdbmreorg.c (gdbm_reorganize): Use GDBM_RCVR_FORCE. * src/gdbmtool.c (main): Always allocate file_name. * src/bucket.c: Put GDBM_DEBUG_OVERRIDE and GDBM_DEBUG_ALLOC in critical places. * src/falloc.c: Likewise. * src/findkey.c: Likewise. * src/gdbmopen.c: Likewise. * src/gdbmstore.c: Likewise. * src/update.c: Likewise. * tests/Makefile.am [GDBM_COND_DEBUG_ENABLE]: Define GDBM_DEBUG_ENABLE. * tests/gtload.c: New options -hook, -recover, -verbose, -backup, -max-failures, -max-failed-keys, and -max-failed-buckets. Attempt recovery after errors.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/bucket.c19
-rw-r--r--src/debug.c155
-rw-r--r--src/falloc.c20
-rw-r--r--src/findkey.c17
-rw-r--r--src/gdbm.h.in4
-rw-r--r--src/gdbmdefs.h20
-rw-r--r--src/gdbmopen.c14
-rw-r--r--src/gdbmreorg.c2
-rw-r--r--src/gdbmstore.c10
-rw-r--r--src/gdbmtool.c4
-rw-r--r--src/recover.c120
-rw-r--r--src/update.c15
13 files changed, 331 insertions, 74 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index af48a1a..0eed6e3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,6 +66,11 @@ libgdbm_la_SOURCES = \
update.c\
version.c
+if GDBM_COND_DEBUG_ENABLE
+ libgdbm_la_SOURCES += debug.c
+ AM_CPPFLAGS += -DGDBM_DEBUG_ENABLE=1
+endif
+
libgdbm_la_LDFLAGS = -version-info $(VI_CURRENT):$(VI_REVISION):$(VI_AGE)
noinst_LIBRARIES = libgdbmapp.a
diff --git a/src/bucket.c b/src/bucket.c
index 7eb3898..cd9575c 100644
--- a/src/bucket.c
+++ b/src/bucket.c
@@ -98,7 +98,8 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index)
dbf->cache_entry->ca_changed = FALSE;
/* Read the bucket. */
- file_pos = __lseek (dbf, bucket_adr, SEEK_SET);
+ file_pos = GDBM_DEBUG_OVERRIDE ("_gdbm_get_bucket:seek-failure",
+ __lseek (dbf, bucket_adr, SEEK_SET));
if (file_pos != bucket_adr)
{
_gdbm_fatal (dbf, _("lseek error"));
@@ -106,7 +107,8 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index)
return -1;
}
- rc = _gdbm_full_read (dbf, dbf->bucket, dbf->header->bucket_size);
+ rc = GDBM_DEBUG_OVERRIDE ("_gdbm_get_bucket:read-failure",
+ _gdbm_full_read (dbf, dbf->bucket, dbf->header->bucket_size));
if (rc)
{
_gdbm_fatal (dbf, gdbm_strerror (rc));
@@ -248,7 +250,8 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
dir_adr = _gdbm_alloc (dbf, dir_size);
if (dir_adr == 0)
return -1;
- new_dir = (off_t *) malloc (dir_size);
+ new_dir = GDBM_DEBUG_ALLOC ("_gdbm_split_bucket:malloc-failure",
+ malloc (dir_size));
if (new_dir == NULL)
{
gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, TRUE);
@@ -286,7 +289,7 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
while (bucket[select]->h_table[elem_loc].hash_value != -1)
elem_loc = (elem_loc + 1) % dbf->header->bucket_elems;
bucket[select]->h_table[elem_loc] = *old_el;
- bucket[select]->count += 1;
+ bucket[select]->count++;
}
/* Allocate avail space for the bucket[1]. */
@@ -378,15 +381,17 @@ _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);
+
+ file_pos = GDBM_DEBUG_OVERRIDE ("_gdbm_write_bucket:seek-failure",
+ __lseek (dbf, ca_entry->ca_adr, SEEK_SET));
if (file_pos != ca_entry->ca_adr)
{
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);
+ rc = GDBM_DEBUG_OVERRIDE ("_gdbm_write_bucket:write-failure",
+ _gdbm_full_write (dbf, ca_entry->ca_bucket, dbf->header->bucket_size));
if (rc)
{
gdbm_set_errno (dbf, rc, TRUE);
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..ceb0f02
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,155 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright 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
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GDBM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "autoconf.h"
+#include "gdbmdefs.h"
+
+struct hook_list
+{
+ struct hook_list *next;
+ struct hook_list *prev;
+ char *id;
+ gdbm_debug_hook hook;
+ void *data;
+ int retval;
+};
+
+static struct hook_list *hook_head, *hook_tail;
+static struct hook_list *hook_recent;
+
+static struct hook_list *
+hook_lookup_or_install (char const *id, int install)
+{
+ struct hook_list *p;
+
+ for (p = hook_head; p; p = p->next)
+ {
+ int res = strcmp (p->id, id);
+ if (res == 0)
+ return p;
+ if (res > 0)
+ break;
+ }
+
+ if (install)
+ {
+ struct hook_list *elt = malloc (sizeof *elt);
+ if (!elt)
+ return NULL;
+ elt->id = strdup (id);
+ if (!elt->id)
+ {
+ SAVE_ERRNO (free (elt));
+ return NULL;
+ }
+ elt->hook = NULL;
+ elt->next = p;
+ if (p)
+ {
+ if (p->prev)
+ p->prev->next = elt;
+ else
+ hook_head = elt;
+ elt->prev = p->prev;
+ }
+ else
+ {
+ elt->prev = hook_tail;
+ if (hook_tail)
+ hook_tail->next = elt;
+ else
+ hook_head = elt;
+ hook_tail = elt;
+ }
+ return elt;
+ }
+
+ return NULL;
+}
+
+static struct hook_list *
+hook_lookup (char const *id)
+{
+ if (!(hook_recent && strcmp (hook_recent->id, id) == 0))
+ hook_recent = hook_lookup_or_install (id, FALSE);
+ return hook_recent;
+}
+
+static void
+hook_remove (char const *id)
+{
+ struct hook_list *p;
+
+ p = hook_lookup (id);
+ if (!p)
+ return;
+
+ hook_recent = NULL;
+
+ if (p->prev)
+ p->prev->next = p->next;
+ else
+ hook_head = p->next;
+
+ if (p->next)
+ p->next->prev = p->prev;
+ else
+ hook_tail = p->prev;
+
+ free (p->id);
+ free (p);
+}
+
+static int
+default_hook (char const *file, int line, char const *id, void *data)
+{
+ fprintf (stderr, "%s:%d: hit debug hook %s\n", file, line, id);
+ return 1;
+}
+
+void
+_gdbm_debug_hook_install (char const *id, gdbm_debug_hook hook, void *data)
+{
+ struct hook_list *p;
+
+ p = hook_lookup_or_install (id, TRUE);
+ p->hook = hook ? hook : default_hook;
+ p->data = data;
+}
+
+void
+_gdbm_debug_hook_remove (char const *id)
+{
+ hook_remove (id);
+}
+
+int
+_gdbm_debug_hook_check (char const *file, int line, char const *id)
+{
+ struct hook_list *p = hook_lookup (id);
+ if (p)
+ return p->retval = p->hook (file, line, id, p->data);
+ return 0;
+}
+
+int
+_gdbm_debug_hook_val (char const *id)
+{
+ struct hook_list *p = hook_lookup (id);
+ if (p)
+ return p->retval;
+ return 0;
+}
diff --git a/src/falloc.c b/src/falloc.c
index 58a9431..8e53a61 100644
--- a/src/falloc.c
+++ b/src/falloc.c
@@ -179,7 +179,8 @@ pop_avail_block (GDBM_FILE dbf)
+ sizeof (avail_block));
/* Allocate space for the block. */
- new_blk = (avail_block *) malloc (new_el.av_size);
+ new_blk = GDBM_DEBUG_ALLOC ("pop_avail_block:malloc-failure",
+ malloc (new_el.av_size));
if (new_blk == NULL)
{
gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, TRUE);
@@ -188,7 +189,8 @@ pop_avail_block (GDBM_FILE dbf)
}
/* Read the block. */
- file_pos = __lseek (dbf, new_el.av_adr, SEEK_SET);
+ file_pos = GDBM_DEBUG_OVERRIDE ("pop_avail_block:lseek-failure",
+ __lseek (dbf, new_el.av_adr, SEEK_SET));
if (file_pos != new_el.av_adr)
{
gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
@@ -196,7 +198,8 @@ pop_avail_block (GDBM_FILE dbf)
return -1;
}
- rc = _gdbm_full_read (dbf, new_blk, new_el.av_size);
+ rc = GDBM_DEBUG_OVERRIDE ("pop_avail_block:read-failure",
+ _gdbm_full_read (dbf, new_blk, new_el.av_size));
if (rc)
{
gdbm_set_errno (dbf, rc, TRUE);
@@ -275,7 +278,8 @@ push_avail_block (GDBM_FILE dbf)
av_adr = new_loc.av_adr;
/* Split the header block. */
- temp = (avail_block *) malloc (av_size);
+ temp = GDBM_DEBUG_ALLOC ("push_avail_block:malloc-failure",
+ malloc (av_size));
if (temp == NULL)
{
gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, TRUE);
@@ -304,15 +308,17 @@ push_avail_block (GDBM_FILE dbf)
_gdbm_free (dbf, new_loc.av_adr, new_loc.av_size);
/* Update the disk. */
- file_pos = __lseek (dbf, av_adr, SEEK_SET);
+ file_pos = GDBM_DEBUG_OVERRIDE ("push_avail_block:lseek-failure",
+ __lseek (dbf, av_adr, SEEK_SET));
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);
+
+ rc = GDBM_DEBUG_OVERRIDE ("push_avail_block:write-failure",
+ _gdbm_full_write (dbf, temp, av_size));
if (rc)
{
gdbm_set_errno (dbf, rc, TRUE);
diff --git a/src/findkey.c b/src/findkey.c
index 3cd90ce..1f56083 100644
--- a/src/findkey.c
+++ b/src/findkey.c
@@ -34,7 +34,7 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc)
int data_size;
off_t file_pos;
data_cache_elem *data_ca;
-
+
/* Is it already in the cache? */
if (dbf->cache_entry->ca_data.elem_loc == elem_loc)
return dbf->cache_entry->ca_data.dptr;
@@ -50,10 +50,13 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc)
data_ca->data_size = data_size;
data_ca->elem_loc = elem_loc;
data_ca->hash_val = dbf->bucket->h_table[elem_loc].hash_value;
- if (key_size+data_size == 0)
+
+ if (GDBM_DEBUG_HOOK ("_gdbm_read_entry:malloc-failure"))
+ data_ca->dptr = NULL;
+ else if (key_size + data_size == 0)
data_ca->dptr = (char *) malloc (1);
else
- data_ca->dptr = (char *) malloc (key_size+data_size);
+ data_ca->dptr = (char *) malloc (key_size + data_size);
if (data_ca->dptr == NULL)
{
gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, FALSE);
@@ -62,8 +65,9 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc)
}
/* Read into the cache. */
- file_pos = __lseek (dbf, dbf->bucket->h_table[elem_loc].data_pointer,
- SEEK_SET);
+ file_pos = GDBM_DEBUG_OVERRIDE ("_gdbm_read_entry:lseek-failure",
+ __lseek (dbf, dbf->bucket->h_table[elem_loc].data_pointer,
+ SEEK_SET));
if (file_pos != dbf->bucket->h_table[elem_loc].data_pointer)
{
gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
@@ -71,7 +75,8 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc)
return NULL;
}
- rc = _gdbm_full_read (dbf, data_ca->dptr, key_size+data_size);
+ rc = GDBM_DEBUG_OVERRIDE ("_gdbm_read_entry:read-failure",
+ _gdbm_full_read (dbf, data_ca->dptr, key_size+data_size));
if (rc)
{
gdbm_set_errno (dbf, rc, TRUE);
diff --git a/src/gdbm.h.in b/src/gdbm.h.in
index dec1ea6..4ee3a11 100644
--- a/src/gdbm.h.in
+++ b/src/gdbm.h.in
@@ -161,7 +161,9 @@ typedef struct gdbm_recovery_s
#define GDBM_RCVR_MAX_FAILURES 0x08 /* max_failures is initialized */
#define GDBM_RCVR_BACKUP 0x10 /* Keep backup copy of the
original database on success */
-
+#define GDBM_RCVR_FORCE 0x20 /* Force recovery by skipping the
+ check pass */
+
extern int gdbm_recover (GDBM_FILE dbf, gdbm_recovery *rcvr, int flags);
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index cdaa1eb..035fbbe 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -250,6 +250,24 @@ struct gdbm_file_info
} \
} \
while (0)
-
+
+/* Debugging hooks */
+#ifdef GDBM_DEBUG_ENABLE
+typedef int (*gdbm_debug_hook) (char const *, int, char const *, void *);
+extern void _gdbm_debug_hook_install (char const *, gdbm_debug_hook, void *);
+extern void _gdbm_debug_hook_remove (char const *);
+extern int _gdbm_debug_hook_check (char const *, int, char const *);
+extern int _gdbm_debug_hook_val (char const *);
+# define GDBM_DEBUG_HOOK(id) _gdbm_debug_hook_check(__FILE__,__LINE__,id)
+# define GDBM_DEBUG_OVERRIDE(id, stmt) \
+ (GDBM_DEBUG_HOOK(id) ? _gdbm_debug_hook_val(id) : (stmt))
+# define GDBM_DEBUG_ALLOC(id, stmt) \
+ (GDBM_DEBUG_HOOK(id) ? NULL : (stmt))
+#else
+# define GDBM_DEBUG_HOOK(id) 0
+# define GDBM_DEBUG_OVERRIDE(id, stmt) (stmt)
+# define GDBM_DEBUG_ALLOC(id, stmt) (stmt)
+#endif
+
/* Now define all the routines in use. */
#include "proto.h"
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index d256a0d..3891b7c 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -490,24 +490,26 @@ gdbm_open (const char *file, int block_size, int flags, int mode,
/* Initialize the bucket cache. */
int
-_gdbm_init_cache(GDBM_FILE dbf, size_t size)
+_gdbm_init_cache (GDBM_FILE dbf, size_t size)
{
int index;
if (dbf->bucket_cache == NULL)
{
- dbf->bucket_cache = (cache_elem *) malloc(sizeof(cache_elem) * size);
- if(dbf->bucket_cache == NULL)
+ dbf->bucket_cache = GDBM_DEBUG_ALLOC ("_gdbm_init_cache:malloc-failure",
+ malloc (sizeof(cache_elem) * size));
+ if (dbf->bucket_cache == NULL)
{
gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, TRUE);
return -1;
}
dbf->cache_size = size;
- for(index = 0; index < size; index++)
+ for (index = 0; index < size; index++)
{
- (dbf->bucket_cache[index]).ca_bucket
- = (hash_bucket *) malloc (dbf->header->bucket_size);
+ (dbf->bucket_cache[index]).ca_bucket =
+ GDBM_DEBUG_ALLOC ("_gdbm_init_cache:bucket-malloc-failure",
+ malloc (dbf->header->bucket_size));
if ((dbf->bucket_cache[index]).ca_bucket == NULL)
{
gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, TRUE);
diff --git a/src/gdbmreorg.c b/src/gdbmreorg.c
index e9b7742..f7723c1 100644
--- a/src/gdbmreorg.c
+++ b/src/gdbmreorg.c
@@ -37,5 +37,5 @@ gdbm_reorganize (GDBM_FILE dbf)
GDBM_ASSERT_CONSISTENCY (dbf, -1);
rcvr.max_failures = 0;
- return gdbm_recover (dbf, &rcvr, GDBM_RCVR_MAX_FAILURES);
+ return gdbm_recover (dbf, &rcvr, GDBM_RCVR_MAX_FAILURES|GDBM_RCVR_FORCE);
}
diff --git a/src/gdbmstore.c b/src/gdbmstore.c
index 7aec604..1d7c648 100644
--- a/src/gdbmstore.c
+++ b/src/gdbmstore.c
@@ -144,7 +144,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
dbf->bucket->h_table[elem_loc].data_size = content.dsize;
/* Write the data to the file. */
- file_pos = __lseek (dbf, file_adr, SEEK_SET);
+ file_pos = GDBM_DEBUG_OVERRIDE ("gdbm_store:seek-failure",
+ __lseek (dbf, file_adr, SEEK_SET));
if (file_pos != file_adr)
{
gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
@@ -152,7 +153,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
return -1;
}
- rc = _gdbm_full_write (dbf, key.dptr, key.dsize);
+ rc = GDBM_DEBUG_OVERRIDE ("gdbm_store:write-1-failure",
+ _gdbm_full_write (dbf, key.dptr, key.dsize));
if (rc)
{
gdbm_set_errno (dbf, rc, TRUE);
@@ -160,7 +162,9 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
return -1;
}
- rc = _gdbm_full_write (dbf, content.dptr, content.dsize);
+ rc = GDBM_DEBUG_OVERRIDE ("gdbm_store:write-2-failure",
+ _gdbm_full_write (dbf,
+ content.dptr, content.dsize));
if (rc)
{
gdbm_set_errno (dbf, rc, TRUE);
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 9c49403..97ba0c1 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -1815,7 +1815,7 @@ main (int argc, char *argv[])
break;
case 'g':
- file_name = optarg;
+ file_name = estrdup (optarg);
break;
case 'q':
@@ -1839,7 +1839,7 @@ main (int argc, char *argv[])
}
if (argc == 1)
- file_name = argv[0];
+ file_name = estrdup (argv[0]);
signal (SIGPIPE, SIG_IGN);
diff --git a/src/recover.c b/src/recover.c
index ad786b3..69644f9 100644
--- a/src/recover.c
+++ b/src/recover.c
@@ -199,6 +199,53 @@ _gdbm_next_bucket_dir (GDBM_FILE dbf, int bucket_dir)
return bucket_dir;
}
+static int
+check_db (GDBM_FILE dbf)
+{
+ int bucket_dir, i;
+ int nbuckets = GDBM_DIR_COUNT (dbf);
+
+ for (bucket_dir = 0; bucket_dir < nbuckets;
+ bucket_dir = _gdbm_next_bucket_dir (dbf, bucket_dir))
+ {
+ if (_gdbm_get_bucket (dbf, bucket_dir))
+ return 1;
+ else
+ {
+ if (dbf->bucket->count < 0
+ || dbf->bucket->count > dbf->header->bucket_elems)
+ return 1;
+ for (i = 0; i < dbf->header->bucket_elems; i++)
+ {
+ char *dptr;
+ datum key;
+ int hashval, bucket, off;
+
+ if (dbf->bucket->h_table[i].hash_value == -1)
+ continue;
+ dptr = _gdbm_read_entry (dbf, i);
+ if (!dptr)
+ return 1;
+
+ key.dptr = dptr;
+ key.dsize = dbf->bucket->h_table[i].key_size;
+
+ if (memcmp (dbf->bucket->h_table[i].key_start, key.dptr,
+ (SMALL < key.dsize ? SMALL : key.dsize)))
+ return 1;
+
+ _gdbm_hash_key (dbf, key, &hashval, &bucket, &off);
+ if (bucket >= nbuckets)
+ return 1;
+ if (hashval != dbf->bucket->h_table[i].hash_value)
+ return 1;
+ if (dbf->dir[bucket] != dbf->dir[bucket_dir])
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
static int
run_recovery (GDBM_FILE dbf, GDBM_FILE new_dbf, gdbm_recovery *rcvr, int flags)
@@ -310,50 +357,53 @@ gdbm_recover (GDBM_FILE dbf, gdbm_recovery *rcvr, int flags)
rcvr->failed_keys = 0;
rcvr->failed_buckets = 0;
rcvr->backup_name = NULL;
-
- len = strlen (dbf->name);
- new_name = malloc (len + sizeof (TMPSUF));
- if (!new_name)
- {
- gdbm_set_errno (NULL, GDBM_MALLOC_ERROR, FALSE);
- return -1;
- }
- strcat (strcpy (new_name, dbf->name), TMPSUF);
-
- fd = mkstemp (new_name);
- if (fd == -1)
+
+ rc = 0;
+ if ((flags & GDBM_RCVR_FORCE) || check_db (dbf))
{
- gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, FALSE);
- free (new_name);
- return -1;
- }
+ len = strlen (dbf->name);
+ new_name = malloc (len + sizeof (TMPSUF));
+ if (!new_name)
+ {
+ gdbm_set_errno (NULL, GDBM_MALLOC_ERROR, FALSE);
+ return -1;
+ }
+ strcat (strcpy (new_name, dbf->name), TMPSUF);
- new_dbf = gdbm_fd_open (fd, new_name, dbf->header->block_size,
- GDBM_WRCREAT
- | (dbf->cloexec ? GDBM_CLOEXEC : 0)
- | GDBM_CLOERROR, dbf->fatal_err);
+ fd = mkstemp (new_name);
+ if (fd == -1)
+ {
+ gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, FALSE);
+ free (new_name);
+ return -1;
+ }
- SAVE_ERRNO (free (new_name));
+ new_dbf = gdbm_fd_open (fd, new_name, dbf->header->block_size,
+ GDBM_WRCREAT
+ | (dbf->cloexec ? GDBM_CLOEXEC : 0)
+ | GDBM_CLOERROR, dbf->fatal_err);
- if (new_dbf == NULL)
- {
- gdbm_set_errno (NULL, GDBM_REORGANIZE_FAILED, FALSE);
- return -1;
- }
+ SAVE_ERRNO (free (new_name));
- rc = run_recovery (dbf, new_dbf, rcvr, flags);
+ if (new_dbf == NULL)
+ {
+ gdbm_set_errno (NULL, GDBM_REORGANIZE_FAILED, FALSE);
+ return -1;
+ }
+
+ rc = run_recovery (dbf, new_dbf, rcvr, flags);
+ if (rc == 0)
+ rc = _gdbm_finish_transfer (dbf, new_dbf, rcvr, flags);
+ else
+ gdbm_close (new_dbf);
+ }
+
if (rc == 0)
{
- rc = _gdbm_finish_transfer (dbf, new_dbf, rcvr, flags);
- if (rc == 0)
- {
- gdbm_clear_error (dbf);
- dbf->need_recovery = FALSE;
- }
+ gdbm_clear_error (dbf);
+ dbf->need_recovery = FALSE;
}
- else
- gdbm_close (new_dbf);
return rc;
}
diff --git a/src/update.c b/src/update.c
index 2ddfa4b..90a6524 100644
--- a/src/update.c
+++ b/src/update.c
@@ -29,8 +29,9 @@ write_header (GDBM_FILE dbf)
{
off_t file_pos; /* Return value for lseek. */
int rc;
-
- file_pos = __lseek (dbf, 0L, SEEK_SET);
+
+ file_pos = GDBM_DEBUG_OVERRIDE ("write_header:lseek-failure",
+ __lseek (dbf, 0L, SEEK_SET));
if (file_pos != 0)
{
gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
@@ -38,7 +39,9 @@ write_header (GDBM_FILE dbf)
return -1;
}
- rc = _gdbm_full_write (dbf, dbf->header, dbf->header->block_size);
+ rc = GDBM_DEBUG_OVERRIDE ("write_header:write-failure",
+ _gdbm_full_write (dbf, dbf->header, dbf->header->block_size));
+
if (rc)
{
gdbm_set_errno (dbf, rc, TRUE);
@@ -92,7 +95,8 @@ _gdbm_end_update (GDBM_FILE dbf)
/* Write the directory. */
if (dbf->directory_changed)
{
- file_pos = __lseek (dbf, dbf->header->dir, SEEK_SET);
+ file_pos = GDBM_DEBUG_OVERRIDE ("_gdbm_end_update:lseek-failure",
+ __lseek (dbf, dbf->header->dir, SEEK_SET));
if (file_pos != dbf->header->dir)
{
gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
@@ -100,7 +104,8 @@ _gdbm_end_update (GDBM_FILE dbf)
return -1;
}
- rc = _gdbm_full_write (dbf, dbf->dir, dbf->header->dir_size);
+ rc = GDBM_DEBUG_OVERRIDE ("_gdbm_end_update:write-dir-failure",
+ _gdbm_full_write (dbf, dbf->dir, dbf->header->dir_size));
if (rc)
{
gdbm_set_errno (dbf, rc, TRUE);

Return to:

Send suggestions and report system problems to the System administrator.