diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gdbmdefs.h | 6 | ||||
-rw-r--r-- | src/gdbmopen.c | 39 |
2 files changed, 38 insertions, 7 deletions
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h index af6f09c..9740b16 100644 --- a/src/gdbmdefs.h +++ b/src/gdbmdefs.h @@ -76,5 +76,5 @@ gdbm_avail_block_valid_p (avail_block const *av) -/* Return true if both AV and the size of AV->av_table are valid */ -extern int gdbm_avail_table_valid_p (GDBM_FILE dbf, - avail_elem const *av, int count); +/* Return true if both AV and the size of AV->av_table are valid. + See comment to this function in gdbmopen.c */ +extern int gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem *av, int count); diff --git a/src/gdbmopen.c b/src/gdbmopen.c index 677f1cf..9747517 100644 --- a/src/gdbmopen.c +++ b/src/gdbmopen.c @@ -58,4 +58,26 @@ bucket_element_count (size_t bucket_size) +static int +avail_comp (void const *a, void const *b) +{ + avail_elem const *ava = a; + avail_elem const *avb = b; + return ava->av_size - avb->av_size; +} + +/* Returns true if the avail array AV[0]@COUNT is valid. + + As a side effect, ensures the array is sorted by element size + in increasing order and restores the ordering if necessary. + + The proper ordering could have been clobbered in versions of GDBM<=1.14, + by a call to _gdbm_put_av_elem with the can_merge parameter set to + TRUE. This happened in two cases: either because the GDBM_COALESCEBLKS + was set, and (quite unfortunately) when _gdbm_put_av_elem was called + from pop_avail_block in falloc.c. The latter case is quite common, + which means that there can be lots of existing databases with broken + ordering of avail arrays. Thus, restoring of the proper ordering + is essential for people to be able to use their existing databases. +*/ int -gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem const *av, int count) +gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem *av, int count) { @@ -63,3 +85,4 @@ gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem const *av, int count) int i; - + int needs_sorting = 0; + prev = 0; @@ -67,8 +90,16 @@ gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem const *av, int count) { - if (!(av->av_size >= prev - && av->av_adr >= dbf->header->bucket_size + if (!(av->av_adr >= dbf->header->bucket_size && av->av_adr + av->av_size <= dbf->header->next_block)) return 0; + if (av->av_size < prev) + needs_sorting = 1; prev = av->av_size; } + + if (needs_sorting && dbf->read_write) + { + GDBM_DEBUG (GDBM_DEBUG_ERR, "restoring sort order"); + qsort (av, count, sizeof av[0], avail_comp); + } + return 1; |