diff options
Diffstat (limited to 'src/gdbmopen.c')
-rw-r--r-- | src/gdbmopen.c | 39 |
1 files changed, 35 insertions, 4 deletions
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 | ||