summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2018-10-18 14:23:07 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2018-10-18 14:23:07 (GMT)
commit852ff1b6e81ce13fdcd1fd4fb272b17d760760b3 (patch) (side-by-side diff)
tree3113d09e84353d47dfd48b237c8b5e2c62eed869
parent2ff4ae9c745d4b9e6ee36468c81554027f66c35b (diff)
downloadgdbm-852ff1b6e81ce13fdcd1fd4fb272b17d760760b3.tar.gz
gdbm-852ff1b6e81ce13fdcd1fd4fb272b17d760760b3.tar.bz2
Attempt recovery in case of invalid next_block header field
* src/gdbmopen.c (validate_header): Return GDBM_NEED_RECOVERY if next_block is invalid. (_gdbm_validate_header): New function. (gdbm_fd_open): Set need_recovery depending on return from validate_header. (gdbm_open): Bail out on invalid value of GDBM_OPENMASK bits. * src/proto.h (_gdbm_validate_header): New proto. * src/recover.c (check_db): Re-validate the header. * src/gdbmtool.c (export_handler): Fix option processing.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/gdbmopen.c55
-rw-r--r--src/gdbmtool.c2
-rw-r--r--src/proto.h2
-rw-r--r--src/recover.c4
4 files changed, 43 insertions, 20 deletions
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index 7ec57e7..fe2527e 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -136,6 +136,7 @@ static int
validate_header (gdbm_file_header const *hdr, struct stat const *st)
{
int dir_size, dir_bits;
+ int result = GDBM_NO_ERROR;
/* Is the magic number good? */
if (hdr->header_magic != GDBM_MAGIC)
@@ -169,8 +170,7 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st)
}
if (hdr->next_block != st->st_size)
- /* FIXME: Should return GDBM_NEED_RECOVERY instead? */
- return GDBM_BAD_HEADER;
+ result = GDBM_NEED_RECOVERY;
/* Make sure dir and dir + dir_size fall within the file boundary */
if (!(hdr->dir > 0
@@ -196,9 +196,20 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st)
!= hdr->avail.size)
return GDBM_BAD_HEADER;
- return 0;
+ return result;
}
-
+
+int
+_gdbm_validate_header (GDBM_FILE dbf)
+{
+ struct stat file_stat;
+
+ if (fstat (dbf->desc, &file_stat))
+ return GDBM_FILE_STAT_ERROR;
+
+ return validate_header (dbf->header, &file_stat);
+}
+
/* Do we have ftruncate? */
static inline int
_gdbm_ftruncate (GDBM_FILE dbf)
@@ -261,7 +272,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->mapped_size = 0;
dbf->mapped_pos = 0;
dbf->mapped_off = 0;
-
+
/* Save name of file. */
dbf->name = strdup (file_name);
if (dbf->name == NULL)
@@ -521,7 +532,11 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
/* Is the header valid? */
rc = validate_header (&partial_header, &file_stat);
- if (rc != GDBM_NO_ERROR)
+ if (rc == GDBM_NEED_RECOVERY)
+ {
+ dbf->need_recovery = 1;
+ }
+ else if (rc != GDBM_NO_ERROR)
{
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
@@ -627,7 +642,8 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->bucket_changed = FALSE;
dbf->second_changed = FALSE;
- GDBM_DEBUG (GDBM_DEBUG_ALL, "%s: opened successfully", dbf->name);
+ GDBM_DEBUG (GDBM_DEBUG_ALL, "%s: opened %s", dbf->name,
+ dbf->need_recovery ? "for recovery" : "successfully");
/* Everything is fine, return the pointer to the file
information structure. */
@@ -664,20 +680,23 @@ gdbm_open (const char *file, int block_size, int flags, int mode,
switch (flags & GDBM_OPENMASK)
{
- case GDBM_READER:
- fbits = O_RDONLY;
- break;
+ case GDBM_READER:
+ fbits = O_RDONLY;
+ break;
- case GDBM_WRITER:
- fbits = O_RDWR;
- break;
+ case GDBM_WRITER:
+ fbits = O_RDWR;
+ break;
- case GDBM_NEWDB:
- fbits = O_RDWR|O_CREAT;
- break;
+ case GDBM_WRCREAT:
+ case GDBM_NEWDB:
+ fbits = O_RDWR|O_CREAT;
+ break;
- default:
- fbits = O_RDWR|O_CREAT;
+ default:
+ errno = EINVAL;
+ GDBM_SET_ERRNO2 (NULL, GDBM_FILE_OPEN_ERROR, FALSE, GDBM_DEBUG_OPEN);
+ return NULL;
}
if (flags & GDBM_CLOEXEC)
fbits |= O_CLOEXEC;
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 8c97e1e..bbadbae 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -969,7 +969,7 @@ export_handler (struct handler_param *param)
int i;
int filemode;
- for (i = 0; i < param->argc; i++)
+ for (i = 1; i < param->argc; i++)
{
if (strcmp (PARAM_STRING (param, i), "truncate") == 0)
flags = GDBM_NEWDB;
diff --git a/src/proto.h b/src/proto.h
index 02f6f9b..e3b6a45 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -53,6 +53,8 @@ void _gdbm_cache_entry_invalidate (GDBM_FILE, int);
int gdbm_avail_block_validate (GDBM_FILE dbf, avail_block *avblk);
int gdbm_bucket_avail_table_validate (GDBM_FILE dbf, hash_bucket *bucket);
+int _gdbm_validate_header (GDBM_FILE dbf);
+
/* From mmap.c */
int _gdbm_mapped_init (GDBM_FILE);
void _gdbm_mapped_unmap (GDBM_FILE);
diff --git a/src/recover.c b/src/recover.c
index a64a1b4..7cc20a2 100644
--- a/src/recover.c
+++ b/src/recover.c
@@ -206,6 +206,8 @@ check_db (GDBM_FILE dbf)
int bucket_dir, i;
int nbuckets = GDBM_DIR_COUNT (dbf);
+ if (_gdbm_validate_header (dbf))
+ return 1;
for (bucket_dir = 0; bucket_dir < nbuckets;
bucket_dir = _gdbm_next_bucket_dir (dbf, bucket_dir))
{
@@ -410,7 +412,7 @@ gdbm_recover (GDBM_FILE dbf, gdbm_recovery *rcvr, int flags)
}
rc = run_recovery (dbf, new_dbf, rcvr, flags);
-
+
if (rc == 0)
rc = _gdbm_finish_transfer (dbf, new_dbf, rcvr, flags);
else

Return to:

Send suggestions and report system problems to the System administrator.