diff options
-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 | |||
@@ -74,9 +74,9 @@ gdbm_avail_block_valid_p (avail_block const *av) | |||
74 | return (av->size > 1 && av->count >= 0 && av->count <= av->size); | 74 | return (av->size > 1 && av->count >= 0 && av->count <= av->size); |
75 | } | 75 | } |
76 | 76 | ||
77 | /* Return true if both AV and the size of AV->av_table are valid */ | 77 | /* Return true if both AV and the size of AV->av_table are valid. |
78 | extern int gdbm_avail_table_valid_p (GDBM_FILE dbf, | 78 | See comment to this function in gdbmopen.c */ |
79 | avail_elem const *av, int count); | 79 | extern int gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem *av, int count); |
80 | 80 | ||
81 | /* The dbm file header keeps track of the current location of the hash | 81 | /* The dbm file header keeps track of the current location of the hash |
82 | directory and the free space in the file. */ | 82 | directory and the free space in the file. */ |
diff --git a/src/gdbmopen.c b/src/gdbmopen.c index 677f1cf..9747517 100644 --- a/src/gdbmopen.c +++ b/src/gdbmopen.c | |||
@@ -56,21 +56,52 @@ bucket_element_count (size_t bucket_size) | |||
56 | return (bucket_size - sizeof (hash_bucket)) / sizeof (bucket_element) + 1; | 56 | return (bucket_size - sizeof (hash_bucket)) / sizeof (bucket_element) + 1; |
57 | } | 57 | } |
58 | 58 | ||
59 | static int | ||
60 | avail_comp (void const *a, void const *b) | ||
61 | { | ||
62 | avail_elem const *ava = a; | ||
63 | avail_elem const *avb = b; | ||
64 | return ava->av_size - avb->av_size; | ||
65 | } | ||
66 | |||
67 | /* Returns true if the avail array AV[0]@COUNT is valid. | ||
68 | |||
69 | As a side effect, ensures the array is sorted by element size | ||
70 | in increasing order and restores the ordering if necessary. | ||
71 | |||
72 | The proper ordering could have been clobbered in versions of GDBM<=1.14, | ||
73 | by a call to _gdbm_put_av_elem with the can_merge parameter set to | ||
74 | TRUE. This happened in two cases: either because the GDBM_COALESCEBLKS | ||
75 | was set, and (quite unfortunately) when _gdbm_put_av_elem was called | ||
76 | from pop_avail_block in falloc.c. The latter case is quite common, | ||
77 | which means that there can be lots of existing databases with broken | ||
78 | ordering of avail arrays. Thus, restoring of the proper ordering | ||
79 | is essential for people to be able to use their existing databases. | ||
80 | */ | ||
59 | int | 81 | int |
60 | gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem const *av, int count) | 82 | gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem *av, int count) |
61 | { | 83 | { |
62 | off_t prev = 0; | 84 | off_t prev = 0; |
63 | int i; | 85 | int i; |
64 | 86 | int needs_sorting = 0; | |
87 | |||
65 | prev = 0; | 88 | prev = 0; |
66 | for (i = 0; i < count; i++, av++) | 89 | for (i = 0; i < count; i++, av++) |
67 | { | 90 | { |
68 | if (!(av->av_size >= prev | 91 | if (!(av->av_adr >= dbf->header->bucket_size |
69 | && av->av_adr >= dbf->header->bucket_size | ||
70 | && av->av_adr + av->av_size <= dbf->header->next_block)) | 92 | && av->av_adr + av->av_size <= dbf->header->next_block)) |
71 | return 0; | 93 | return 0; |
94 | if (av->av_size < prev) | ||
95 | needs_sorting = 1; | ||
72 | prev = av->av_size; | 96 | prev = av->av_size; |
73 | } | 97 | } |
98 | |||
99 | if (needs_sorting && dbf->read_write) | ||
100 | { | ||
101 | GDBM_DEBUG (GDBM_DEBUG_ERR, "restoring sort order"); | ||
102 | qsort (av, count, sizeof av[0], avail_comp); | ||
103 | } | ||
104 | |||
74 | return 1; | 105 | return 1; |
75 | } | 106 | } |
76 | 107 | ||