summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2021-07-28 10:28:03 +0300
committerSergey Poznyakoff <gray@gnu.org>2021-07-28 10:28:03 +0300
commit35e81092b99608d8a4f1ecf55c21bbd4d3c5eda0 (patch)
tree8a9a97ed39faaef4e1407db002a16898e1599738
parentf06b1bb17beed10e56b2875b8dc0f4f0e5838bcc (diff)
downloadgdbm-35e81092b99608d8a4f1ecf55c21bbd4d3c5eda0.tar.gz
Prepare structs gdbm_file_header and gdbm_file_info for changes.
* src/gdbmconst.h (GDBM_NUMSYNC_MAGIC32) (GDBM_NUMSYNC_MAGIC64) (GDBM_NUMSYNC_MAGIC32_SWAP) (GDBM_NUMSYNC_MAGIC64_SWAP): New constants. * src/gdbmdefs.h (gdbm_file_header): Move avail to a union in anticipation of further changes. (gdbm_file_info) <avail, avail_size>: New members. (GDBM_HEADER_AVAIL_SIZE): Redefine. * src/gdbmopen.c (GDBM_NUMSYNC_MAGIC): New define. (validate_header_std) (validate_header_numsync): New functions. (validate_header): Use one of these depending on the magic number. (gdbm_fd_open): Initialize new members of gdbm_file_info. * src/avail.c: Use the GDBM_FILE avail pointer. * src/falloc.c: Likewise. * src/gdbmtool.c: Likewise.
-rw-r--r--src/avail.c11
-rw-r--r--src/falloc.c73
-rw-r--r--src/gdbmconst.h8
-rw-r--r--src/gdbmdefs.h16
-rw-r--r--src/gdbmopen.c129
-rw-r--r--src/gdbmtool.c7
6 files changed, 159 insertions, 85 deletions
diff --git a/src/avail.c b/src/avail.c
index 9031de8..79eaeee 100644
--- a/src/avail.c
+++ b/src/avail.c
@@ -214,17 +214,18 @@ gdbm_avail_traverse (GDBM_FILE dbf,
int rc = 0;
GDBM_ASSERT_CONSISTENCY (dbf, -1);
- if (gdbm_avail_block_validate (dbf, &dbf->header->avail,
+ if (gdbm_avail_block_validate (dbf, dbf->avail,
GDBM_HEADER_AVAIL_SIZE (dbf)))
return -1;
- if (off_map_lookup (&map, offsetof (gdbm_file_header, avail)))
+ // FIXME
+ if (off_map_lookup (&map, offsetof (gdbm_file_header, v.avail_tab)))
{
GDBM_SET_ERRNO (dbf, GDBM_MALLOC_ERROR, FALSE);
return -1;
}
- size = ((((size_t)dbf->header->avail.size * sizeof (avail_elem)) >> 1)
+ size = ((((size_t)dbf->avail->size * sizeof (avail_elem)) >> 1)
+ sizeof (avail_block));
blk = malloc (size);
if (!blk)
@@ -234,9 +235,9 @@ gdbm_avail_traverse (GDBM_FILE dbf,
return -1;
}
- if (!(cb && cb (&dbf->header->avail, 0, data)))
+ if (!(cb && cb (dbf->avail, 0, data)))
{
- n = dbf->header->avail.next_block;
+ n = dbf->avail->next_block;
while (n)
{
rc = off_map_lookup (&map, n);
diff --git a/src/falloc.c b/src/falloc.c
index 4598064..979d77a 100644
--- a/src/falloc.c
+++ b/src/falloc.c
@@ -79,14 +79,13 @@ _gdbm_alloc (GDBM_FILE dbf, int num_bytes)
{
/* 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))
+ if ((dbf->avail->count <= (dbf->avail->size >> 1))
+ && (dbf->avail->next_block != 0))
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);
+ av_el = get_elem (num_bytes, dbf->avail->av_table, &dbf->avail->count);
if (av_el.av_size == 0)
/* Get another full block from end of file. */
av_el = get_block (num_bytes, dbf);
@@ -128,13 +127,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)
+ if (dbf->avail->count == dbf->avail->size)
{
if (push_avail_block (dbf))
return -1;
}
- _gdbm_put_av_elem (temp, dbf->header->avail.av_table,
- &dbf->header->avail.count, dbf->coalesce_blocks);
+ _gdbm_put_av_elem (temp, dbf->avail->av_table,
+ &dbf->avail->count, dbf->coalesce_blocks);
dbf->header_changed = TRUE;
}
else
@@ -145,13 +144,13 @@ _gdbm_free (GDBM_FILE dbf, off_t file_adr, int num_bytes)
&dbf->bucket->av_count, dbf->coalesce_blocks);
else
{
- if (dbf->header->avail.count == dbf->header->avail.size)
+ if (dbf->avail->count == dbf->avail->size)
{
if (push_avail_block (dbf))
return -1;
}
- _gdbm_put_av_elem (temp, dbf->header->avail.av_table,
- &dbf->header->avail.count, dbf->coalesce_blocks);
+ _gdbm_put_av_elem (temp, dbf->avail->av_table,
+ &dbf->avail->count, dbf->coalesce_blocks);
dbf->header_changed = TRUE;
}
}
@@ -181,7 +180,7 @@ pop_avail_block (GDBM_FILE dbf)
avail_block *new_blk;
int index;
- if (dbf->header->avail.count == dbf->header->avail.size)
+ if (dbf->avail->count == dbf->avail->size)
{
/* We're kind of stuck here, so we re-split the header in order to
avoid crashing. Sigh. */
@@ -190,8 +189,8 @@ pop_avail_block (GDBM_FILE dbf)
}
/* Set up variables. */
- new_el.av_adr = dbf->header->avail.next_block;
- new_el.av_size = ( ( (dbf->header->avail.size * sizeof (avail_elem)) >> 1)
+ new_el.av_adr = dbf->avail->next_block;
+ new_el.av_size = ( ( (dbf->avail->size * sizeof (avail_elem)) >> 1)
+ sizeof (avail_block));
/* Allocate space for the block. */
@@ -225,15 +224,15 @@ pop_avail_block (GDBM_FILE dbf)
while (index < new_blk->count)
{
while (index < new_blk->count
- && dbf->header->avail.count < dbf->header->avail.size)
+ && dbf->avail->count < dbf->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);
+ dbf->avail->av_table,
+ &dbf->avail->count, TRUE);
index++;
}
- if (dbf->header->avail.count == dbf->header->avail.size)
+ if (dbf->avail->count == dbf->avail->size)
{
/* We're kind of stuck here, so we re-split the header in order to
avoid crashing. Sigh. */
@@ -246,14 +245,15 @@ pop_avail_block (GDBM_FILE dbf)
}
/* Fix next_block, as well. */
- dbf->header->avail.next_block = new_blk->next_block;
+ dbf->avail->next_block = new_blk->next_block;
/* We changed the header. */
+ //FIXME: or avail block, when it is separate
dbf->header_changed = TRUE;
/* 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)
+ if (dbf->avail->count == dbf->avail->size)
{
/* We're kind of stuck here, so we re-split the header in order to
avoid crashing. Sigh. */
@@ -264,8 +264,7 @@ pop_avail_block (GDBM_FILE dbf)
}
}
- _gdbm_put_av_elem (new_el, dbf->header->avail.av_table,
- &dbf->header->avail.count, TRUE);
+ _gdbm_put_av_elem (new_el, dbf->avail->av_table, &dbf->avail->count, TRUE);
free (new_blk);
return 0;
@@ -286,12 +285,11 @@ push_avail_block (GDBM_FILE dbf)
int rc;
/* Caclulate the size of the split block. */
- av_size = ( (dbf->header->avail.size * sizeof (avail_elem)) >> 1)
+ av_size = ( (dbf->avail->size * sizeof (avail_elem)) >> 1)
+ sizeof (avail_block);
/* Get address in file for new av_size bytes. */
- new_loc = get_elem (av_size, dbf->header->avail.av_table,
- &dbf->header->avail.count);
+ new_loc = get_elem (av_size, dbf->avail->av_table, &dbf->avail->count);
if (new_loc.av_size == 0)
new_loc = get_block (av_size, dbf);
av_adr = new_loc.av_adr;
@@ -306,19 +304,18 @@ push_avail_block (GDBM_FILE dbf)
}
/* Set the size to be correct AFTER the pop_avail_block. */
- temp->size = dbf->header->avail.size;
+ temp->size = dbf->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++)
+ temp->next_block = dbf->avail->next_block;
+ dbf->avail->next_block = av_adr;
+ for (index = 1; index < dbf->avail->count; index++)
if ( (index & 0x1) == 1) /* Index is odd. */
- temp->av_table[temp->count++] = dbf->header->avail.av_table[index];
+ temp->av_table[temp->count++] = dbf->avail->av_table[index];
else
- dbf->header->avail.av_table[index>>1]
- = dbf->header->avail.av_table[index];
+ dbf->avail->av_table[index>>1] = dbf->avail->av_table[index];
/* Update the header avail count to previous size divided by 2. */
- dbf->header->avail.count >>= 1;
+ dbf->avail->count >>= 1;
rc = 0;
do
@@ -512,10 +509,10 @@ adjust_bucket_avail (GDBM_FILE dbf)
/* Can we add more entries to the bucket? */
if (dbf->bucket->av_count < third)
{
- if (dbf->header->avail.count > 0)
+ if (dbf->avail->count > 0)
{
- dbf->header->avail.count -= 1;
- av_el = dbf->header->avail.av_table[dbf->header->avail.count];
+ dbf->avail->count -= 1;
+ av_el = dbf->avail->av_table[dbf->avail->count];
_gdbm_put_av_elem (av_el, dbf->bucket->bucket_avail,
&dbf->bucket->av_count, dbf->coalesce_blocks);
dbf->bucket_changed = TRUE;
@@ -525,7 +522,7 @@ adjust_bucket_avail (GDBM_FILE dbf)
/* Is there too much in the bucket? */
while (dbf->bucket->av_count > BUCKET_AVAIL-third
- && dbf->header->avail.count < dbf->header->avail.size)
+ && dbf->avail->count < dbf->avail->size)
{
av_el = get_elem (0, dbf->bucket->bucket_avail, &dbf->bucket->av_count);
if (av_el.av_size == 0)
@@ -533,8 +530,8 @@ adjust_bucket_avail (GDBM_FILE dbf)
GDBM_SET_ERRNO (dbf, GDBM_BAD_AVAIL, TRUE);
return -1;
}
- _gdbm_put_av_elem (av_el, dbf->header->avail.av_table,
- &dbf->header->avail.count,
+ _gdbm_put_av_elem (av_el, dbf->avail->av_table,
+ &dbf->avail->count,
dbf->coalesce_blocks);
dbf->bucket_changed = TRUE;
}
diff --git a/src/gdbmconst.h b/src/gdbmconst.h
index d466ac5..a04bd0e 100644
--- a/src/gdbmconst.h
+++ b/src/gdbmconst.h
@@ -27,13 +27,19 @@
alas... We just have to assume that an OMAGIC file is readable. */
#define GDBM_OMAGIC 0x13579ace /* Original magic number. */
-#define GDBM_MAGIC32 0x13579acd /* New 32bit magic number. */
+#define GDBM_MAGIC32 0x13579acd /* New 32bit magic number. */
#define GDBM_MAGIC64 0x13579acf /* New 64bit magic number. */
#define GDBM_OMAGIC_SWAP 0xce9a5713 /* OMAGIC swapped. */
#define GDBM_MAGIC32_SWAP 0xcd9a5713 /* MAGIC32 swapped. */
#define GDBM_MAGIC64_SWAP 0xcf9a5713 /* MAGIC64 swapped. */
+#define GDBM_NUMSYNC_MAGIC32 0x13579ad0
+#define GDBM_NUMSYNC_MAGIC64 0x13579ad1
+
+#define GDBM_NUMSYNC_MAGIC32_SWAP 0xd09a5713
+#define GDBM_NUMSYNC_MAGIC64_SWAP 0xd19a5713
+
/* Size of a hash value, in bits */
#define GDBM_HASH_BITS 31
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index ef38d28..c5fbb18 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -80,9 +80,12 @@ typedef struct
int bucket_size; /* Size in bytes of a hash bucket struct. */
int bucket_elems; /* Number of elements in a hash bucket. */
off_t next_block; /* The next unallocated block address. */
- avail_block avail; /* This must be last because of the pseudo
- array in avail. This avail grows to fill
- the entire block. */
+ union
+ {
+ avail_block avail_tab; /* This must be last because of the pseudo
+ array in avail. This avail grows to fill
+ the entire block. */
+ } v;
} gdbm_file_header;
/* The dbm hash bucket element contains the full 31 bit hash value, the
@@ -227,6 +230,10 @@ struct gdbm_file_info
/* The file header holds information about the database. */
gdbm_file_header *header;
+
+ /* The table of available file space */
+ avail_block *avail;
+ size_t avail_size;
/* The hash table directory from extendable hashing. See Fagin et al,
ACM Trans on Database Systems, Vol 4, No 3. Sept 1979, 315-344 */
@@ -287,8 +294,7 @@ struct gdbm_file_info
#define GDBM_DIR_COUNT(db) ((db)->header->dir_size / sizeof (off_t))
-#define GDBM_HEADER_AVAIL_SIZE(dbf) \
- ((dbf)->header->block_size - offsetof (gdbm_file_header, avail))
+#define GDBM_HEADER_AVAIL_SIZE(db) ((db)->avail_size)
/* Execute CODE without clobbering errno */
#define SAVE_ERRNO(code) \
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index 544195b..a532b93 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -25,8 +25,10 @@
/* Determine our native magic number and bail if we can't. */
#if SIZEOF_OFF_T == 4
# define GDBM_MAGIC GDBM_MAGIC32
+# define GDBM_NUMSYNC_MAGIC GDBM_NUMSYNC_MAGIC32
#elif SIZEOF_OFF_T == 8
# define GDBM_MAGIC GDBM_MAGIC64
+# define GDBM_NUMSYNC_MAGIC GDBM_NUMSYNC_MAGIC64
#else
# error "Unsupported off_t size, contact GDBM maintainer. What crazy system is this?!?"
#endif
@@ -58,38 +60,14 @@ bucket_element_count (size_t bucket_size)
}
static int
-validate_header (gdbm_file_header const *hdr, struct stat const *st)
+validate_header_std (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)
- {
- switch (hdr->header_magic)
- {
- case GDBM_OMAGIC:
- /* OK */
- break;
-
- case GDBM_OMAGIC_SWAP:
- case GDBM_MAGIC32_SWAP:
- case GDBM_MAGIC64_SWAP:
- return GDBM_BYTE_SWAPPED;
- case GDBM_MAGIC32:
- case GDBM_MAGIC64:
- return GDBM_BAD_FILE_OFFSET;
-
- default:
- return GDBM_BAD_MAGIC_NUMBER;
- }
- }
-
if (!(hdr->block_size > 0
&& hdr->block_size > sizeof (gdbm_file_header)
&& hdr->block_size - sizeof (gdbm_file_header) >=
- sizeof(hdr->avail.av_table[0])))
+ sizeof(hdr->v.avail_tab.av_table[0])))
{
return GDBM_BLOCK_SIZE_ERROR;
}
@@ -124,12 +102,93 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st)
return GDBM_BAD_HEADER;
if (((hdr->block_size - sizeof (gdbm_file_header)) / sizeof(avail_elem) + 1)
- != hdr->avail.size)
+ != hdr->v.avail_tab.size)
+ return GDBM_BAD_HEADER;
+
+ return result;
+}
+
+static int
+validate_header_numsync (gdbm_file_header const *hdr, struct stat const *st)
+{
+ int result = GDBM_NO_ERROR;
+
+ if (!(hdr->block_size > 0
+ && hdr->block_size > sizeof (gdbm_file_header))) //FIXME
+ {
+ return GDBM_BLOCK_SIZE_ERROR;
+ }
+
+ /* Technically speaking, the condition below should read
+ hdr->next_block != st->st_size
+ However, gdbm versions prior to commit 4e819c98 could leave
+ hdr->next_block pointing beyond current end of file. To ensure
+ backward compatibility with these versions, the condition has been
+ slackened to this: */
+ if (hdr->next_block < st->st_size)
+ result = GDBM_NEED_RECOVERY;
+
+ /* Make sure dir and dir + dir_size fall within the file boundary */
+ if (!(hdr->dir > 0
+ && hdr->dir < st->st_size
+ && hdr->dir_size > 0
+ && hdr->dir + hdr->dir_size < st->st_size))
return GDBM_BAD_HEADER;
+ compute_directory_size (hdr->block_size, &dir_size, &dir_bits);
+ if (!(hdr->dir_size >= dir_size))
+ return GDBM_BAD_HEADER;
+ compute_directory_size (hdr->dir_size, &dir_size, &dir_bits);
+ if (hdr->dir_bits != dir_bits)
+ return GDBM_BAD_HEADER;
+
+ if (!(hdr->bucket_size > sizeof(hash_bucket)))
+ return GDBM_BAD_HEADER;
+
+ if (hdr->bucket_elems != bucket_element_count (hdr->bucket_size))
+ return GDBM_BAD_HEADER;
+
+ //FIXME: Verify avail offset
return result;
}
+static int
+validate_header (gdbm_file_header const *hdr, struct stat const *st)
+{
+ int dir_size, dir_bits;
+
+ /* Is the magic number good? */
+ switch (hdr->header_magic)
+ {
+ case GDBM_OMAGIC:
+ case GDBM_MAGIC:
+ return validate_header_std (hdr, st);
+
+ case GDBM_NUMSYNC_MAGIC:
+ return validate_header_numsync (hdr, st);
+
+ default:
+ switch (hdr->header_magic)
+ {
+ case GDBM_OMAGIC_SWAP:
+ case GDBM_MAGIC32_SWAP:
+ case GDBM_MAGIC64_SWAP:
+ case GDBM_NUMSYNC_MAGIC32_SWAP:
+ case GDBM_NUMSYNC_MAGIC64_SWAP:
+ return GDBM_BYTE_SWAPPED;
+
+ case GDBM_MAGIC32:
+ case GDBM_MAGIC64:
+ case GDBM_NUMSYNC_MAGIC32:
+ case GDBM_NUMSYNC_MAGIC64:
+ return GDBM_BAD_FILE_OFFSET;
+
+ default:
+ return GDBM_BAD_MAGIC_NUMBER;
+ }
+ }
+}
+
int
_gdbm_validate_header (GDBM_FILE dbf)
{
@@ -142,7 +201,7 @@ _gdbm_validate_header (GDBM_FILE dbf)
rc = validate_header (dbf->header, &file_stat);
if (rc == 0)
{
- if (gdbm_avail_block_validate (dbf, &dbf->header->avail,
+ if (gdbm_avail_block_validate (dbf, &dbf->header->v.avail_tab,
GDBM_HEADER_AVAIL_SIZE (dbf)))
rc = GDBM_BAD_AVAIL;
}
@@ -395,11 +454,11 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->dir[index] = 2*dbf->header->block_size;
/* Initialize the active avail block. */
- dbf->header->avail.size
+ dbf->header->v.avail_tab.size
= ( (dbf->header->block_size - sizeof (gdbm_file_header))
/ sizeof (avail_elem)) + 1;
- dbf->header->avail.count = 0;
- dbf->header->avail.next_block = 0;
+ dbf->header->v.avail_tab.count = 0;
+ dbf->header->v.avail_tab.next_block = 0;
dbf->header->next_block = 4*dbf->header->block_size;
/* Write initial configuration to the file. */
@@ -502,7 +561,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
}
memcpy (dbf->header, &partial_header, sizeof (partial_header));
- if (_gdbm_full_read (dbf, &dbf->header->avail.av_table[1],
+ if (_gdbm_full_read (dbf, &dbf->header->v.avail_tab.av_table[1],
dbf->header->block_size - sizeof (gdbm_file_header)))
{
if (!(flags & GDBM_CLOERROR))
@@ -511,7 +570,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
return NULL;
}
- if (gdbm_avail_block_validate (dbf, &dbf->header->avail,
+ if (gdbm_avail_block_validate (dbf, &dbf->header->v.avail_tab,
GDBM_HEADER_AVAIL_SIZE (dbf)))
{
if (!(flags & GDBM_CLOERROR))
@@ -555,6 +614,10 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
}
+ //FIXME dbf->avail_off = offsetof (gdbm_file_header, avail_tab);
+ dbf->avail = &dbf->header->v.avail_tab;
+ dbf->avail_size = (dbf->header->block_size - offsetof (gdbm_file_header, v.avail_tab));
+
#if HAVE_MMAP
if (!(flags & GDBM_NOMMAP))
{
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index c201ef8..66b3811 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -797,10 +797,11 @@ print_header_handler (struct handler_param *param)
fprintf (fp, _(" header magic = %x\n"), gdbm_file->header->header_magic);
fprintf (fp, _(" next block = %lu\n"),
(unsigned long) gdbm_file->header->next_block);
- fprintf (fp, _(" avail size = %d\n"), gdbm_file->header->avail.size);
- fprintf (fp, _(" avail count = %d\n"), gdbm_file->header->avail.count);
+ //FIXME
+ fprintf (fp, _(" avail size = %d\n"), gdbm_file->header->v.avail_tab.size);
+ fprintf (fp, _(" avail count = %d\n"), gdbm_file->header->v.avail_tab.count);
fprintf (fp, _(" avail nx blk = %lu\n"),
- (unsigned long) gdbm_file->header->avail.next_block);
+ (unsigned long) gdbm_file->header->v.avail_tab.next_block);
}
/* hash KEY - hash the key */