summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/falloc.c28
-rw-r--r--src/gdbmdefs.h3
-rw-r--r--src/gdbmopen.c49
-rw-r--r--src/gdbmtool.c10
-rw-r--r--src/proto.h3
5 files changed, 51 insertions, 42 deletions
diff --git a/src/falloc.c b/src/falloc.c
index 94ff70f..4598064 100644
--- a/src/falloc.c
+++ b/src/falloc.c
@@ -31,6 +31,23 @@ static int push_avail_block (GDBM_FILE);
static int pop_avail_block (GDBM_FILE);
static int adjust_bucket_avail (GDBM_FILE);
+int
+_gdbm_avail_block_read (GDBM_FILE dbf, avail_block *avblk, size_t size)
+{
+ int rc;
+
+ rc = _gdbm_full_read (dbf, avblk, size);
+ if (rc)
+ {
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: error reading av_table: %s",
+ dbf->name, gdbm_db_strerror (dbf));
+ }
+ else
+ rc = gdbm_avail_block_validate (dbf, avblk, size);
+ return rc;
+}
+
/* Allocate space in the file DBF for a block NUM_BYTES in length. Return
the file address of the start of the block.
@@ -159,7 +176,6 @@ _gdbm_free (GDBM_FILE dbf, off_t file_adr, int num_bytes)
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;
@@ -197,15 +213,7 @@ pop_avail_block (GDBM_FILE dbf)
return -1;
}
- rc = _gdbm_full_read (dbf, new_blk, new_el.av_size);
- if (rc)
- {
- free (new_blk);
- _gdbm_fatal (dbf, gdbm_db_strerror (dbf));
- return -1;
- }
-
- if (gdbm_avail_block_validate (dbf, new_blk))
+ if (_gdbm_avail_block_read (dbf, new_blk, new_el.av_size))
{
free (new_blk);
_gdbm_fatal (dbf, gdbm_db_strerror (dbf));
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index ea9df3e..b1e53f9 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -45,7 +45,7 @@ off_t_sum_ok (off_t a, off_t b)
/* The available file space is stored in an "avail" table. The one with
most activity is contained in the file header. (See below.) When that
- one filles up, it is split in half and half is pushed on an "avail
+ one fills up, it is split in half and half is pushed on an "avail
stack." When the active avail table is empty and the "avail stack" is
not empty, the top of the stack is popped into the active avail table. */
@@ -95,7 +95,6 @@ typedef struct
the entire block. */
} gdbm_file_header;
-
/* The dbm hash bucket element contains the full 31 bit hash value, the
"pointer" to the key and data (stored together) with their sizes. It also
has a small part of the actual key value. It is used to verify the first
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index 7806c7a..cbb7195 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -106,9 +106,10 @@ gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem *av, int count)
}
int
-gdbm_avail_block_validate (GDBM_FILE dbf, avail_block *avblk)
+gdbm_avail_block_validate (GDBM_FILE dbf, avail_block *avblk, size_t size)
{
- if (!(gdbm_avail_block_valid_p (avblk)
+ if (!(((size - sizeof (avail_block)) / sizeof (avail_elem) + 1) >= avblk->count
+ && gdbm_avail_block_valid_p (avblk)
&& gdbm_avail_table_valid_p (dbf, avblk->av_table, avblk->count)))
{
GDBM_SET_ERRNO (dbf, GDBM_BAD_AVAIL, TRUE);
@@ -197,22 +198,35 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st)
if (hdr->bucket_elems != bucket_element_count (hdr->bucket_size))
return GDBM_BAD_HEADER;
- if (((hdr->block_size - sizeof (gdbm_file_header)) / sizeof(avail_elem) + 1)
- != hdr->avail.size)
- return GDBM_BAD_HEADER;
-
return result;
}
+/*
+ * GDBM file header is read in two chunks: first, all fields up to avail,
+ * then the avail block. PARTIAL_HEADER_SIZE is the size of the first
+ * chunk, and HEADER_AVAIL_SIZE(dbf) gives the size of the second one.
+ */
+#define PARTIAL_HEADER_SIZE (offsetof (gdbm_file_header, avail))
+#define HEADER_AVAIL_SIZE(dbf) \
+ ((dbf)->header->block_size - PARTIAL_HEADER_SIZE)
+
int
_gdbm_validate_header (GDBM_FILE dbf)
{
struct stat file_stat;
-
+ int rc;
+
if (fstat (dbf->desc, &file_stat))
return GDBM_FILE_STAT_ERROR;
- return validate_header (dbf->header, &file_stat);
+ rc = validate_header (dbf->header, &file_stat);
+ if (rc == 0)
+ {
+ if (gdbm_avail_block_validate (dbf, &dbf->header->avail,
+ HEADER_AVAIL_SIZE (dbf)))
+ rc = GDBM_BAD_AVAIL;
+ }
+ return rc;
}
/* Do we have ftruncate? */
@@ -526,7 +540,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
int rc;
/* Read the partial file header. */
- if (_gdbm_full_read (dbf, &partial_header, sizeof (gdbm_file_header)))
+ if (_gdbm_full_read (dbf, &partial_header, PARTIAL_HEADER_SIZE))
{
GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
"%s: error reading partial header: %s",
@@ -563,27 +577,16 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
return NULL;
}
- memcpy (dbf->header, &partial_header, sizeof (gdbm_file_header));
- if (_gdbm_full_read (dbf, &dbf->header->avail.av_table[1],
- dbf->header->block_size - sizeof (gdbm_file_header)))
+ memcpy (dbf->header, &partial_header, PARTIAL_HEADER_SIZE);
+ if (_gdbm_avail_block_read (dbf, &dbf->header->avail,
+ HEADER_AVAIL_SIZE (dbf)))
{
- GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
- "%s: error reading av_table: %s",
- dbf->name, gdbm_db_strerror (dbf));
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
SAVE_ERRNO (gdbm_close (dbf));
return NULL;
}
- if (gdbm_avail_block_validate (dbf, &dbf->header->avail))
- {
- if (!(flags & GDBM_CLOERROR))
- dbf->desc = -1;
- SAVE_ERRNO (gdbm_close (dbf));
- return NULL;
- }
-
/* Allocate space for the hash table directory. */
dbf->dir = malloc (dbf->header->dir_size);
if (dbf->dir == NULL)
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 20e85ea..1d6b8dd 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -286,7 +286,7 @@ _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
/* Initialize the variables for a pass throught the avail stack. */
temp = dbf->header->avail.next_block;
- size = (dbf->header->avail.size * sizeof (avail_elem))
+ size = ((dbf->header->avail.size - 1) * sizeof (avail_elem))
+ sizeof (avail_block);
av_stk = emalloc (size);
@@ -299,7 +299,7 @@ _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
break;
}
- if (_gdbm_full_read (dbf, av_stk, size))
+ if (_gdbm_avail_block_read (dbf, av_stk, size))
{
terror ("read: %s", gdbm_db_strerror (dbf));
break;
@@ -308,10 +308,8 @@ _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
/* Print the block! */
fprintf (fp, _("\nblock = %d\nsize = %d\ncount = %d\n"), temp,
av_stk->size, av_stk->count);
- if (gdbm_avail_block_validate (dbf, av_stk) == 0)
- av_table_display (av_stk->av_table, av_stk->count, fp);
- else
- terror ("%s", gdbm_strerror (GDBM_BAD_AVAIL));
+ av_table_display (av_stk->av_table, av_stk->count, fp);
+
temp = av_stk->next_block;
}
free (av_stk);
diff --git a/src/proto.h b/src/proto.h
index df5d83d..c4b1a08 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -32,6 +32,7 @@ int _gdbm_cache_flush (GDBM_FILE dbf);
off_t _gdbm_alloc (GDBM_FILE, int);
int _gdbm_free (GDBM_FILE, off_t, int);
void _gdbm_put_av_elem (avail_elem, avail_elem [], int *, int);
+int _gdbm_avail_block_read (GDBM_FILE dbf, avail_block *avblk, size_t size);
/* From findkey.c */
char *_gdbm_read_entry (GDBM_FILE, int);
@@ -48,7 +49,7 @@ int _gdbm_end_update (GDBM_FILE);
void _gdbm_fatal (GDBM_FILE, const char *);
/* From gdbmopen.c */
-int gdbm_avail_block_validate (GDBM_FILE dbf, avail_block *avblk);
+int gdbm_avail_block_validate (GDBM_FILE dbf, avail_block *avblk, size_t size);
int gdbm_bucket_avail_table_validate (GDBM_FILE dbf, hash_bucket *bucket);
int _gdbm_validate_header (GDBM_FILE dbf);