diff options
-rw-r--r-- | Makefile.am | 16 | ||||
-rw-r--r-- | NEWS | 31 | ||||
-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 |
10 files changed, 157 insertions, 20 deletions
diff --git a/Makefile.am b/Makefile.am index 6e00dec..ecc03df 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,3 +26,4 @@ AM_DISTCHECK_CONFIGURE_FLAGS = --enable-libgdbm-compat -dist-hook: +.PHONY: set-dist-date +set-dist-date: rm -f $(distdir)/src/version.c; \ @@ -32,2 +33,15 @@ dist-hook: +dist-hook: ChangeLog set-dist-date + @if test -f ChangeLog && test -f NEWS; then \ + PATCHLEV=`echo "$(PACKAGE_VERSION)" | sed -r "s/[0-9]+\.[0-9]+\.?//"`;\ + if test $${PATCHLEV:-0} -lt 50; then \ + if grep -q FIXME NEWS; then \ + echo >&2 "*** NEWS file contains FIXMEs"; \ + echo >&2 "*** Aborting"; \ + exit 1; \ + fi; \ + fi; \ + fi + + gen_start_date = 2016-07-08 @@ -1,2 +1,2 @@ -GNU dbm NEWS -- history of user-visible changes. 2018-05-19 +GNU dbm NEWS -- history of user-visible changes. 2018-05-24 Copyright (C) 1990-2018 Free Software Foundation, Inc. @@ -8,2 +8,4 @@ Version 1.14.90 +FIXME: BUMP VI_MAJOR + * Implement database consistency checks @@ -14,2 +16,29 @@ Version 1.14.90 +* Commands can be given to gdbmtool in the command line + +The syntax is: + + gdbmtool DBNAME COMMAND [ARGS...] + +Multiple commands are separated by semicolon (take care to escape it), +e.g.: + + gdbmtool t.db count\; avail + +* Fixed data conversion bugs in storing structured keys or content + +* New member in the gdbm_recovery structure: duplicate_keys. + +Upon return from gdbm_recover, this member holds the number of keys +that were not recovered, because the same key has already been stored +in the database. The actual number of stored keys is thus +recovered_keys - duplicate_keys. + +* New error codes. + + GDBM_BAD_BUCKET "Malformed bucket header" + GDBM_BAD_HEADER "Malformed database file header" + GDBM_BAD_AVAIL "Malformed avail_block" + GDBM_BAD_HASH_TABLE "Malformed hash table" + diff --git a/src/findkey.c b/src/findkey.c index 7638b04..bd9fd83 100644 --- a/src/findkey.c +++ b/src/findkey.c @@ -24,3 +24,17 @@ - +int +gdbm_bucket_element_valid_p (GDBM_FILE dbf, int elem_loc) +{ + return + elem_loc < dbf->header->bucket_elems + && dbf->bucket->h_table[elem_loc].hash_value != -1 + && dbf->bucket->h_table[elem_loc].key_size >= 0 + && off_t_sum_ok (dbf->bucket->h_table[elem_loc].data_pointer, + dbf->bucket->h_table[elem_loc].key_size) + && dbf->bucket->h_table[elem_loc].data_size >= 0 + && off_t_sum_ok (dbf->bucket->h_table[elem_loc].data_pointer + + dbf->bucket->h_table[elem_loc].key_size, + dbf->bucket->h_table[elem_loc].data_size); +} + /* Read the data found in bucket entry ELEM_LOC in file DBF and @@ -36,3 +50,3 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc) data_cache_elem *data_ca; - + /* Is it already in the cache? */ @@ -41,2 +55,8 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc) + if (!gdbm_bucket_element_valid_p (dbf, elem_loc)) + { + GDBM_SET_ERRNO (dbf, GDBM_BAD_HASH_TABLE, TRUE); + return NULL; + } + /* Set sizes and pointers. */ 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 @@ -154,2 +154,3 @@ typedef struct gdbm_recovery_s size_t failed_buckets; + size_t duplicate_keys; char *backup_name; @@ -224,5 +225,6 @@ extern int gdbm_copy_meta (GDBM_FILE dst, GDBM_FILE src); # define GDBM_BAD_AVAIL 34 +# define GDBM_BAD_HASH_TABLE 35 # define _GDBM_MIN_ERRNO 0 -# define _GDBM_MAX_ERRNO GDBM_BAD_AVAIL +# define _GDBM_MAX_ERRNO GDBM_BAD_HASH_TABLE diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h index 5305b0d..1bb519b 100644 --- a/src/gdbmdefs.h +++ b/src/gdbmdefs.h @@ -28,2 +28,18 @@ +/* The width in bits of the integer type or expression T. */ +#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) + +#define SIGNED_TYPE_MAXIMUM(t) \ + ((t) ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1)) + +/* Maximum value for off_t */ +#define OFF_T_MAX SIGNED_TYPE_MAXIMUM (off_t) + +/* Return true if A can be added to B without integer overflow */ +static inline off_t +off_t_sum_ok (off_t a, off_t b) +{ + return OFF_T_MAX - a >= b; +} + /* The type definitions are next. */ @@ -95,2 +111,3 @@ typedef struct +extern int gdbm_bucket_element_valid_p (GDBM_FILE dbf, int elem_loc); diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c index 896bf70..52cfe30 100644 --- a/src/gdbmerrno.c +++ b/src/gdbmerrno.c @@ -136,3 +136,4 @@ const char * const gdbm_errlist[_GDBM_MAX_ERRNO+1] = { [GDBM_BAD_HEADER] = N_("Malformed database file header"), - [GDBM_BAD_AVAIL] = N_("Malforemd avail_block") + [GDBM_BAD_AVAIL] = N_("Malformed avail_block"), + [GDBM_BAD_HASH_TABLE] = N_("Malformed hash table") }; diff --git a/src/gdbmtool.c b/src/gdbmtool.c index 33bdf93..9c6eebe 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -554,3 +554,3 @@ err_printer (void *data GDBM_ARG_UNUSED, char const *fmt, ...) -/* recover verbose backup max-failed-keys=N max-failed-buckets=N max-failures=N */ +/* recover sumamry verbose backup max-failed-keys=N max-failed-buckets=N max-failures=N */ void @@ -563,4 +563,5 @@ recover_handler (struct handler_param *param) char *p; + int summary = 0; - for (i = 1; i < param->argc; i++) + for (i = 0; i < param->argc; i++) { @@ -572,2 +573,6 @@ recover_handler (struct handler_param *param) } + else if (strcmp (arg, "summary") == 0) + { + summary = 1; + } else if (strcmp (arg, "backup") == 0) @@ -619,2 +624,15 @@ recover_handler (struct handler_param *param) fprintf (param->fp, _("Recovery succeeded.\n")); + if (summary) + { + fprintf (param->fp, + _("Keys recovered: %lu, failed: %lu, duplicate: %lu\n"), + (unsigned long) rcvr.recovered_keys, + (unsigned long) rcvr.failed_keys, + (unsigned long) rcvr.duplicate_keys); + fprintf (param->fp, + _("Buckets recovered: %lu, failed: %lu\n"), + (unsigned long) rcvr.recovered_buckets, + (unsigned long) rcvr.failed_buckets); + } + if (rcvr.backup_name) @@ -927,3 +945,3 @@ export_handler (struct handler_param *param) - for (i = 1; i < param->argc; i++) + for (i = 0; i < param->argc; i++) { @@ -961,3 +979,3 @@ import_handler (struct handler_param *param) - for (i = 1; i < param->argc; i++) + for (i = 0; i < param->argc; i++) { @@ -1222,2 +1240,3 @@ struct command command_tab[] = { { { "[verbose]", GDBM_ARG_STRING }, + { "[summary]", GDBM_ARG_STRING }, { "[backup]", GDBM_ARG_STRING }, @@ -46,4 +46,11 @@ /* Return the sum of the currently mapped size and DELTA */ -# define SUM_FILE_SIZE(dbf, delta) \ - ((dbf)->mapped_off + (dbf)->mapped_size + (delta)) +static inline off_t +SUM_FILE_SIZE (GDBM_FILE dbf, off_t delta) +{ + if (delta >= 0 + && off_t_sum_ok (dbf->mapped_off, dbf->mapped_size) + && off_t_sum_ok (dbf->mapped_off + dbf->mapped_size, delta)) + return dbf->mapped_off + dbf->mapped_size + delta; + return -1; +} @@ -184,2 +191,13 @@ _gdbm_mapped_remap (GDBM_FILE dbf, off_t size, int flag) + if (size < 0) + { + errno = EINVAL; + GDBM_SET_ERRNO (dbf, GDBM_FILE_SEEK_ERROR, TRUE); + return -1; + } + + if (size < dbf->mapped_size) + /* Nothing to do */ + return 0; + if (_gdbm_file_size (dbf, &file_size)) diff --git a/src/recover.c b/src/recover.c index d6d4ff9..721c23f 100644 --- a/src/recover.c +++ b/src/recover.c @@ -314,11 +314,26 @@ run_recovery (GDBM_FILE dbf, GDBM_FILE new_dbf, gdbm_recovery *rcvr, int flags) { - if (flags & GDBM_RCVR_ERRFUN) - rcvr->errfun (rcvr->data, - _("fatal: can't store element %d:%d (%lu:%d): %s"), - bucket_dir, i, - (unsigned long) dbf->bucket->h_table[i].data_pointer, - dbf->bucket->h_table[i].key_size + switch (gdbm_last_errno (new_dbf)) + { + case GDBM_CANNOT_REPLACE: + rcvr->duplicate_keys++; + if (flags & GDBM_RCVR_ERRFUN) + rcvr->errfun (rcvr->data, + _("ignoring duplicate key %d:%d (%lu:%d)"), + bucket_dir, i, + (unsigned long) dbf->bucket->h_table[i].data_pointer, + dbf->bucket->h_table[i].key_size + + dbf->bucket->h_table[i].data_size); + break; + + default: + if (flags & GDBM_RCVR_ERRFUN) + rcvr->errfun (rcvr->data, + _("fatal: can't store element %d:%d (%lu:%d): %s"), + bucket_dir, i, + (unsigned long) dbf->bucket->h_table[i].data_pointer, + dbf->bucket->h_table[i].key_size + dbf->bucket->h_table[i].data_size, - gdbm_db_strerror (new_dbf)); - return -1; + gdbm_db_strerror (new_dbf)); + return -1; + } } @@ -358,2 +373,3 @@ gdbm_recover (GDBM_FILE dbf, gdbm_recovery *rcvr, int flags) rcvr->failed_buckets = 0; + rcvr->duplicate_keys = 0; rcvr->backup_name = NULL; diff --git a/src/systems.h b/src/systems.h index 66955dd..c678573 100644 --- a/src/systems.h +++ b/src/systems.h @@ -35,2 +35,3 @@ #include <errno.h> +#include <limits.h> |