diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-05-24 11:35:24 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-05-24 11:35:24 +0300 |
commit | 371bb85fe378ffd0ed6ddc81985d450cef5835a3 (patch) | |
tree | 6ab2d142b7aa1f9b29ec50b891c8293774964209 /src | |
parent | f82d0b213fd2cdce80dc891906fba8d589115664 (diff) | |
download | gdbm-371bb85fe378ffd0ed6ddc81985d450cef5835a3.tar.gz gdbm-371bb85fe378ffd0ed6ddc81985d450cef5835a3.tar.bz2 |
More error checking; improve gdbm_recover
* Makefile.am (set-dist-date): New rule
(dist-hook): Catch FIXMEs in NEWS.
* NEWS: Updated.
* src/findkey.c (gdbm_bucket_element_valid_p): New function.
(_gdbm_read_entry): Validate the retrieved bucket element.
* src/gdbm.h.in (gdbm_recovery): New member: duplicate_keys.
(GDBM_BAD_HASH_TABLE): New error code.
* src/gdbmdefs.h (TYPE_WIDTH,SIGNED_TYPE_MAXIMUM)
(OFF_T_MAX): New defines.
(off_t_sum_ok): New function.
(gdbm_bucket_element_valid_p): New prototype.
* src/gdbmerrno.c: Support for GDBM_BAD_HASH_TABLE code.
* src/gdbmtool.c (recover_handler): Fix argument counting.
New argument 'summary' prints statistics summary at the end
of the run.
(export_handler,import_handler): Fix argument counting.
* src/mmap.c (SUM_FILE_SIZE): Rewrite as inlined function.
Add error checking.
(_gdbm_mapped_remap): More error checking.
* src/recover.c (run_recovery): Don't bail out on GDBM_CANNOT_REPLACE.
(gdbm_recover): Initialize duplicate_keys
* src/systems.h: Include limits.h
Diffstat (limited to 'src')
-rw-r--r-- | src/findkey.c | 24 | ||||
-rw-r--r-- | src/gdbm.h.in | 4 | ||||
-rw-r--r-- | src/gdbmdefs.h | 17 | ||||
-rw-r--r-- | src/gdbmerrno.c | 3 | ||||
-rw-r--r-- | src/gdbmtool.c | 27 | ||||
-rw-r--r-- | src/mmap.c | 22 | ||||
-rw-r--r-- | src/recover.c | 32 | ||||
-rw-r--r-- | src/systems.h | 1 |
8 files changed, 112 insertions, 18 deletions
diff --git a/src/findkey.c b/src/findkey.c index 7638b04..bd9fd83 100644 --- a/src/findkey.c +++ b/src/findkey.c | |||
@@ -19,29 +19,49 @@ | |||
19 | 19 | ||
20 | /* Include system configuration before all else. */ | 20 | /* Include system configuration before all else. */ |
21 | #include "autoconf.h" | 21 | #include "autoconf.h" |
22 | 22 | ||
23 | #include "gdbmdefs.h" | 23 | #include "gdbmdefs.h" |
24 | 24 | ||
25 | 25 | int | |
26 | gdbm_bucket_element_valid_p (GDBM_FILE dbf, int elem_loc) | ||
27 | { | ||
28 | return | ||
29 | elem_loc < dbf->header->bucket_elems | ||
30 | && dbf->bucket->h_table[elem_loc].hash_value != -1 | ||
31 | && dbf->bucket->h_table[elem_loc].key_size >= 0 | ||
32 | && off_t_sum_ok (dbf->bucket->h_table[elem_loc].data_pointer, | ||
33 | dbf->bucket->h_table[elem_loc].key_size) | ||
34 | && dbf->bucket->h_table[elem_loc].data_size >= 0 | ||
35 | && off_t_sum_ok (dbf->bucket->h_table[elem_loc].data_pointer | ||
36 | + dbf->bucket->h_table[elem_loc].key_size, | ||
37 | dbf->bucket->h_table[elem_loc].data_size); | ||
38 | } | ||
39 | |||
26 | /* Read the data found in bucket entry ELEM_LOC in file DBF and | 40 | /* Read the data found in bucket entry ELEM_LOC in file DBF and |
27 | return a pointer to it. Also, cache the read value. */ | 41 | return a pointer to it. Also, cache the read value. */ |
28 | 42 | ||
29 | char * | 43 | char * |
30 | _gdbm_read_entry (GDBM_FILE dbf, int elem_loc) | 44 | _gdbm_read_entry (GDBM_FILE dbf, int elem_loc) |
31 | { | 45 | { |
32 | int rc; | 46 | int rc; |
33 | int key_size; | 47 | int key_size; |
34 | int data_size; | 48 | int data_size; |
35 | off_t file_pos; | 49 | off_t file_pos; |
36 | data_cache_elem *data_ca; | 50 | data_cache_elem *data_ca; |
37 | 51 | ||
38 | /* Is it already in the cache? */ | 52 | /* Is it already in the cache? */ |
39 | if (dbf->cache_entry->ca_data.elem_loc == elem_loc) | 53 | if (dbf->cache_entry->ca_data.elem_loc == elem_loc) |
40 | return dbf->cache_entry->ca_data.dptr; | 54 | return dbf->cache_entry->ca_data.dptr; |
41 | 55 | ||
56 | if (!gdbm_bucket_element_valid_p (dbf, elem_loc)) | ||
57 | { | ||
58 | GDBM_SET_ERRNO (dbf, GDBM_BAD_HASH_TABLE, TRUE); | ||
59 | return NULL; | ||
60 | } | ||
61 | |||
42 | /* Set sizes and pointers. */ | 62 | /* Set sizes and pointers. */ |
43 | key_size = dbf->bucket->h_table[elem_loc].key_size; | 63 | key_size = dbf->bucket->h_table[elem_loc].key_size; |
44 | data_size = dbf->bucket->h_table[elem_loc].data_size; | 64 | data_size = dbf->bucket->h_table[elem_loc].data_size; |
45 | data_ca = &dbf->cache_entry->ca_data; | 65 | data_ca = &dbf->cache_entry->ca_data; |
46 | 66 | ||
47 | /* Set up the cache. */ | 67 | /* Set up the cache. */ |
diff --git a/src/gdbm.h.in b/src/gdbm.h.in index 61d5707..e576c69 100644 --- a/src/gdbm.h.in +++ b/src/gdbm.h.in | |||
@@ -149,12 +149,13 @@ typedef struct gdbm_recovery_s | |||
149 | /* Output members. | 149 | /* Output members. |
150 | The gdbm_recover function fills these before returning. */ | 150 | The gdbm_recover function fills these before returning. */ |
151 | size_t recovered_keys; | 151 | size_t recovered_keys; |
152 | size_t recovered_buckets; | 152 | size_t recovered_buckets; |
153 | size_t failed_keys; | 153 | size_t failed_keys; |
154 | size_t failed_buckets; | 154 | size_t failed_buckets; |
155 | size_t duplicate_keys; | ||
155 | char *backup_name; | 156 | char *backup_name; |
156 | } gdbm_recovery; | 157 | } gdbm_recovery; |
157 | 158 | ||
158 | #define GDBM_RCVR_DEFAULT 0x00 /* Default settings */ | 159 | #define GDBM_RCVR_DEFAULT 0x00 /* Default settings */ |
159 | #define GDBM_RCVR_ERRFUN 0x01 /* errfun is initialized */ | 160 | #define GDBM_RCVR_ERRFUN 0x01 /* errfun is initialized */ |
160 | #define GDBM_RCVR_MAX_FAILED_KEYS 0x02 /* max_failed_keys is initialized */ | 161 | #define GDBM_RCVR_MAX_FAILED_KEYS 0x02 /* max_failed_keys is initialized */ |
@@ -219,15 +220,16 @@ extern int gdbm_copy_meta (GDBM_FILE dst, GDBM_FILE src); | |||
219 | # define GDBM_NEED_RECOVERY 29 | 220 | # define GDBM_NEED_RECOVERY 29 |
220 | # define GDBM_BACKUP_FAILED 30 | 221 | # define GDBM_BACKUP_FAILED 30 |
221 | # define GDBM_DIR_OVERFLOW 31 | 222 | # define GDBM_DIR_OVERFLOW 31 |
222 | # define GDBM_BAD_BUCKET 32 | 223 | # define GDBM_BAD_BUCKET 32 |
223 | # define GDBM_BAD_HEADER 33 | 224 | # define GDBM_BAD_HEADER 33 |
224 | # define GDBM_BAD_AVAIL 34 | 225 | # define GDBM_BAD_AVAIL 34 |
226 | # define GDBM_BAD_HASH_TABLE 35 | ||
225 | 227 | ||
226 | # define _GDBM_MIN_ERRNO 0 | 228 | # define _GDBM_MIN_ERRNO 0 |
227 | # define _GDBM_MAX_ERRNO GDBM_BAD_AVAIL | 229 | # define _GDBM_MAX_ERRNO GDBM_BAD_HASH_TABLE |
228 | 230 | ||
229 | /* This one was never used and will be removed in the future */ | 231 | /* This one was never used and will be removed in the future */ |
230 | # define GDBM_UNKNOWN_UPDATE GDBM_UNKNOWN_ERROR | 232 | # define GDBM_UNKNOWN_UPDATE GDBM_UNKNOWN_ERROR |
231 | 233 | ||
232 | typedef int gdbm_error; | 234 | typedef int gdbm_error; |
233 | extern int *gdbm_errno_location (void); | 235 | extern int *gdbm_errno_location (void); |
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h index 5305b0d..1bb519b 100644 --- a/src/gdbmdefs.h +++ b/src/gdbmdefs.h | |||
@@ -23,12 +23,28 @@ | |||
23 | #define DEFAULT_TEXT_DOMAIN PACKAGE | 23 | #define DEFAULT_TEXT_DOMAIN PACKAGE |
24 | #include "gettext.h" | 24 | #include "gettext.h" |
25 | 25 | ||
26 | #define _(s) gettext (s) | 26 | #define _(s) gettext (s) |
27 | #define N_(s) s | 27 | #define N_(s) s |
28 | 28 | ||
29 | /* The width in bits of the integer type or expression T. */ | ||
30 | #define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) | ||
31 | |||
32 | #define SIGNED_TYPE_MAXIMUM(t) \ | ||
33 | ((t) ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1)) | ||
34 | |||
35 | /* Maximum value for off_t */ | ||
36 | #define OFF_T_MAX SIGNED_TYPE_MAXIMUM (off_t) | ||
37 | |||
38 | /* Return true if A can be added to B without integer overflow */ | ||
39 | static inline off_t | ||
40 | off_t_sum_ok (off_t a, off_t b) | ||
41 | { | ||
42 | return OFF_T_MAX - a >= b; | ||
43 | } | ||
44 | |||
29 | /* The type definitions are next. */ | 45 | /* The type definitions are next. */ |
30 | 46 | ||
31 | /* The available file space is stored in an "avail" table. The one with | 47 | /* The available file space is stored in an "avail" table. The one with |
32 | most activity is contained in the file header. (See below.) When that | 48 | most activity is contained in the file header. (See below.) When that |
33 | one filles up, it is split in half and half is pushed on an "avail | 49 | one filles up, it is split in half and half is pushed on an "avail |
34 | stack." When the active avail table is empty and the "avail stack" is | 50 | stack." When the active avail table is empty and the "avail stack" is |
@@ -90,12 +106,13 @@ typedef struct | |||
90 | off_t data_pointer; /* The file address of the key record. The | 106 | off_t data_pointer; /* The file address of the key record. The |
91 | data record directly follows the key. */ | 107 | data record directly follows the key. */ |
92 | int key_size; /* Size of key data in the file. */ | 108 | int key_size; /* Size of key data in the file. */ |
93 | int data_size; /* Size of associated data in the file. */ | 109 | int data_size; /* Size of associated data in the file. */ |
94 | } bucket_element; | 110 | } bucket_element; |
95 | 111 | ||
112 | extern int gdbm_bucket_element_valid_p (GDBM_FILE dbf, int elem_loc); | ||
96 | 113 | ||
97 | /* A bucket is a small hash table. This one consists of a number of | 114 | /* A bucket is a small hash table. This one consists of a number of |
98 | bucket elements plus some bookkeeping fields. The number of elements | 115 | bucket elements plus some bookkeeping fields. The number of elements |
99 | depends on the optimum blocksize for the storage device and on a | 116 | depends on the optimum blocksize for the storage device and on a |
100 | parameter given at file creation time. This bucket takes one block. | 117 | parameter given at file creation time. This bucket takes one block. |
101 | When one of these tables gets full, it is split into two hash buckets. | 118 | When one of these tables gets full, it is split into two hash buckets. |
diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c index 896bf70..52cfe30 100644 --- a/src/gdbmerrno.c +++ b/src/gdbmerrno.c | |||
@@ -131,13 +131,14 @@ const char * const gdbm_errlist[_GDBM_MAX_ERRNO+1] = { | |||
131 | [GDBM_ERR_FILE_MODE] = N_("Failed to restore file mode"), | 131 | [GDBM_ERR_FILE_MODE] = N_("Failed to restore file mode"), |
132 | [GDBM_NEED_RECOVERY] = N_("Database needs recovery"), | 132 | [GDBM_NEED_RECOVERY] = N_("Database needs recovery"), |
133 | [GDBM_BACKUP_FAILED] = N_("Failed to create backup copy"), | 133 | [GDBM_BACKUP_FAILED] = N_("Failed to create backup copy"), |
134 | [GDBM_DIR_OVERFLOW] = N_("Bucket directory overflow"), | 134 | [GDBM_DIR_OVERFLOW] = N_("Bucket directory overflow"), |
135 | [GDBM_BAD_BUCKET] = N_("Malformed bucket header"), | 135 | [GDBM_BAD_BUCKET] = N_("Malformed bucket header"), |
136 | [GDBM_BAD_HEADER] = N_("Malformed database file header"), | 136 | [GDBM_BAD_HEADER] = N_("Malformed database file header"), |
137 | [GDBM_BAD_AVAIL] = N_("Malforemd avail_block") | 137 | [GDBM_BAD_AVAIL] = N_("Malformed avail_block"), |
138 | [GDBM_BAD_HASH_TABLE] = N_("Malformed hash table") | ||
138 | }; | 139 | }; |
139 | 140 | ||
140 | const char * | 141 | const char * |
141 | gdbm_strerror (gdbm_error error) | 142 | gdbm_strerror (gdbm_error error) |
142 | { | 143 | { |
143 | if (error < _GDBM_MIN_ERRNO || error > _GDBM_MAX_ERRNO) | 144 | if (error < _GDBM_MIN_ERRNO || error > _GDBM_MAX_ERRNO) |
diff --git a/src/gdbmtool.c b/src/gdbmtool.c index 33bdf93..9c6eebe 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c | |||
@@ -549,30 +549,35 @@ err_printer (void *data GDBM_ARG_UNUSED, char const *fmt, ...) | |||
549 | va_start (ap, fmt); | 549 | va_start (ap, fmt); |
550 | vfprintf (stderr, fmt, ap); | 550 | vfprintf (stderr, fmt, ap); |
551 | va_end (ap); | 551 | va_end (ap); |
552 | fprintf (stderr, "\n"); | 552 | fprintf (stderr, "\n"); |
553 | } | 553 | } |
554 | 554 | ||
555 | /* recover verbose backup max-failed-keys=N max-failed-buckets=N max-failures=N */ | 555 | /* recover sumamry verbose backup max-failed-keys=N max-failed-buckets=N max-failures=N */ |
556 | void | 556 | void |
557 | recover_handler (struct handler_param *param) | 557 | recover_handler (struct handler_param *param) |
558 | { | 558 | { |
559 | gdbm_recovery rcvr; | 559 | gdbm_recovery rcvr; |
560 | int flags = 0; | 560 | int flags = 0; |
561 | int rc; | 561 | int rc; |
562 | int i; | 562 | int i; |
563 | char *p; | 563 | char *p; |
564 | int summary = 0; | ||
564 | 565 | ||
565 | for (i = 1; i < param->argc; i++) | 566 | for (i = 0; i < param->argc; i++) |
566 | { | 567 | { |