diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-07-28 10:28:03 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-07-28 10:28:03 +0300 |
commit | 35e81092b99608d8a4f1ecf55c21bbd4d3c5eda0 (patch) | |
tree | 8a9a97ed39faaef4e1407db002a16898e1599738 | |
parent | f06b1bb17beed10e56b2875b8dc0f4f0e5838bcc (diff) | |
download | gdbm-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.c | 11 | ||||
-rw-r--r-- | src/falloc.c | 73 | ||||
-rw-r--r-- | src/gdbmconst.h | 8 | ||||
-rw-r--r-- | src/gdbmdefs.h | 16 | ||||
-rw-r--r-- | src/gdbmopen.c | 129 | ||||
-rw-r--r-- | src/gdbmtool.c | 7 |
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 */ |