aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-05-24 11:35:24 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-05-24 11:35:24 +0300
commit371bb85fe378ffd0ed6ddc81985d450cef5835a3 (patch)
tree6ab2d142b7aa1f9b29ec50b891c8293774964209 /src
parentf82d0b213fd2cdce80dc891906fba8d589115664 (diff)
downloadgdbm-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.c24
-rw-r--r--src/gdbm.h.in4
-rw-r--r--src/gdbmdefs.h17
-rw-r--r--src/gdbmerrno.c3
-rw-r--r--src/gdbmtool.c27
-rw-r--r--src/mmap.c22
-rw-r--r--src/recover.c32
-rw-r--r--src/systems.h1
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 25int
26gdbm_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
29char * 43char *
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
232typedef int gdbm_error; 234typedef int gdbm_error;
233extern int *gdbm_errno_location (void); 235extern 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 */
39static inline off_t
40off_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
112extern 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
140const char * 141const char *
141gdbm_strerror (gdbm_error error) 142gdbm_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 */
556void 556void
557recover_handler (struct handler_param *param) 557recover_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 {