summaryrefslogtreecommitdiffabout
path: root/src
Unidiff
Diffstat (limited to 'src') (more/less context) (show whitespace changes)
-rw-r--r--src/findkey.c20
-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.c16
-rw-r--r--src/systems.h1
8 files changed, 102 insertions, 8 deletions
diff --git a/src/findkey.c b/src/findkey.c
index 7638b04..bd9fd83 100644
--- a/src/findkey.c
+++ b/src/findkey.c
@@ -13,41 +13,61 @@
13 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details. 15 GNU General Public License for more details.
16 16
17 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
18 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */ 18 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
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
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}
25 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. */
48 if (data_ca->dptr != NULL) free (data_ca->dptr); 68 if (data_ca->dptr != NULL) free (data_ca->dptr);
49 data_ca->key_size = key_size; 69 data_ca->key_size = key_size;
50 data_ca->data_size = data_size; 70 data_ca->data_size = data_size;
51 data_ca->elem_loc = elem_loc; 71 data_ca->elem_loc = elem_loc;
52 data_ca->hash_val = dbf->bucket->h_table[elem_loc].hash_value; 72 data_ca->hash_val = dbf->bucket->h_table[elem_loc].hash_value;
53 73
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
@@ -143,24 +143,25 @@ typedef struct gdbm_recovery_s
143 void *data; 143 void *data;
144 144
145 size_t max_failed_keys; 145 size_t max_failed_keys;
146 size_t max_failed_buckets; 146 size_t max_failed_buckets;
147 size_t max_failures; 147 size_t max_failures;
148 148
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 */
161#define GDBM_RCVR_MAX_FAILED_BUCKETS 0x04 /* max_failed_buckets is initialized */ 162#define GDBM_RCVR_MAX_FAILED_BUCKETS 0x04 /* max_failed_buckets is initialized */
162#define GDBM_RCVR_MAX_FAILURES 0x08 /* max_failures is initialized */ 163#define GDBM_RCVR_MAX_FAILURES 0x08 /* max_failures is initialized */
163#define GDBM_RCVR_BACKUP 0x10 /* Keep backup copy of the 164#define GDBM_RCVR_BACKUP 0x10 /* Keep backup copy of the
164 original database on success */ 165 original database on success */
165#define GDBM_RCVR_FORCE 0x20 /* Force recovery by skipping the 166#define GDBM_RCVR_FORCE 0x20 /* Force recovery by skipping the
166 check pass */ 167 check pass */
@@ -213,27 +214,28 @@ extern int gdbm_copy_meta (GDBM_FILE dst, GDBM_FILE src);
213 # define GDBM_BAD_OPEN_FLAGS 23 214 # define GDBM_BAD_OPEN_FLAGS 23
214# define GDBM_FILE_STAT_ERROR 24 215# define GDBM_FILE_STAT_ERROR 24
215# define GDBM_FILE_EOF 25 216# define GDBM_FILE_EOF 25
216# define GDBM_NO_DBNAME 26 217# define GDBM_NO_DBNAME 26
217# define GDBM_ERR_FILE_OWNER 27 218# define GDBM_ERR_FILE_OWNER 27
218# define GDBM_ERR_FILE_MODE 28 219# define GDBM_ERR_FILE_MODE 28
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_ERRNO0 228 # define _GDBM_MIN_ERRNO0
227 # define _GDBM_MAX_ERRNOGDBM_BAD_AVAIL 229 # define _GDBM_MAX_ERRNOGDBM_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);
234#define gdbm_errno (*gdbm_errno_location ()) 236#define gdbm_errno (*gdbm_errno_location ())
235extern const char * const gdbm_errlist[]; 237extern const char * const gdbm_errlist[];
236extern int const gdbm_syserr[]; 238extern int const gdbm_syserr[];
237 239
238extern gdbm_error gdbm_last_errno (GDBM_FILE dbf); 240extern gdbm_error gdbm_last_errno (GDBM_FILE dbf);
239extern int gdbm_last_syserr (GDBM_FILE dbf); 241extern int gdbm_last_syserr (GDBM_FILE dbf);
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index 5305b0d..1bb519b 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -17,24 +17,40 @@
17 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
18 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */ 18 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
19 19
20#include "systems.h" 20#include "systems.h"
21#include "gdbmconst.h" 21#include "gdbmconst.h"
22#include "gdbm.h" 22#include "gdbm.h"
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
35 not empty, the top of the stack is popped into the active avail table. */ 51 not empty, the top of the stack is popped into the active avail table. */
36 52
37/* The following structure is the element of the avaliable table. */ 53/* The following structure is the element of the avaliable table. */
38typedef struct 54typedef struct
39{ 55{
40 int av_size; /* The size of the available block. */ 56 int av_size; /* The size of the available block. */
@@ -84,24 +100,25 @@ typedef struct
84 key. */ 100 key. */
85 101
86typedef struct 102typedef struct
87{ 103{
88 int hash_value; /* The complete 31 bit value. */ 104 int hash_value; /* The complete 31 bit value. */
89 char key_start[SMALL]; /* Up to the first SMALL bytes of the key. */ 105 char key_start[SMALL]; /* Up to the first SMALL bytes of the key. */
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.
102 The contents are split between them by the use of the first few bits 119 The contents are split between them by the use of the first few bits
103 of the 31 bit hash function. The location in a bucket is the hash 120 of the 31 bit hash function. The location in a bucket is the hash
104 value modulo the size of the bucket. The in-memory images of the 121 value modulo the size of the bucket. The in-memory images of the
105 buckets are allocated by malloc using a calculated size depending of 122 buckets are allocated by malloc using a calculated size depending of
106 the file system buffer size. To speed up write, each bucket will have 123 the file system buffer size. To speed up write, each bucket will have
107 BUCKET_AVAIL avail elements with the bucket. */ 124 BUCKET_AVAIL avail elements with the bucket. */
diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c
index 896bf70..52cfe30 100644
--- a/src/gdbmerrno.c
+++ b/src/gdbmerrno.c
@@ -125,25 +125,26 @@ const char * const gdbm_errlist[_GDBM_MAX_ERRNO+1] = {
125 [GDBM_BAD_FILE_OFFSET] = N_("File header assumes wrong off_t size"), 125 [GDBM_BAD_FILE_OFFSET] = N_("File header assumes wrong off_t size"),
126 [GDBM_BAD_OPEN_FLAGS] = N_("Bad file flags"), 126 [GDBM_BAD_OPEN_FLAGS] = N_("Bad file flags"),
127 [GDBM_FILE_STAT_ERROR] = N_("Cannot stat file"), 127 [GDBM_FILE_STAT_ERROR] = N_("Cannot stat file"),
128 [GDBM_FILE_EOF] = N_("Unexpected end of file"), 128 [GDBM_FILE_EOF] = N_("Unexpected end of file"),
129 [GDBM_NO_DBNAME] = N_("Database name not given"), 129 [GDBM_NO_DBNAME] = N_("Database name not given"),
130 [GDBM_ERR_FILE_OWNER] = N_("Failed to restore file owner"), 130 [GDBM_ERR_FILE_OWNER] = N_("Failed to restore file owner"),
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)
144 error = GDBM_UNKNOWN_ERROR; 145 error = GDBM_UNKNOWN_ERROR;
145 return gettext (gdbm_errlist[error]); 146 return gettext (gdbm_errlist[error]);
146} 147}
147 148
148char const * 149char const *
149gdbm_db_strerror (GDBM_FILE dbf) 150gdbm_db_strerror (GDBM_FILE dbf)
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 33bdf93..9c6eebe 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -543,42 +543,47 @@ reorganize_handler (struct handler_param *param GDBM_ARG_UNUSED)
543 543
544static void 544static void
545err_printer (void *data GDBM_ARG_UNUSED, char const *fmt, ...) 545err_printer (void *data GDBM_ARG_UNUSED, char const *fmt, ...)
546{ 546{
547 va_list ap; 547 va_list ap;
548 548
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 {
567 char *arg = PARAM_STRING (param, i); 568 char *arg = PARAM_STRING (param, i);
568 if (strcmp (arg, "verbose") == 0) 569 if (strcmp (arg, "verbose") == 0)
569 { 570 {
570 rcvr.errfun = err_printer; 571 rcvr.errfun = err_printer;
571 flags |= GDBM_RCVR_ERRFUN; 572 flags |= GDBM_RCVR_ERRFUN;
572 } 573 }
574 else if (strcmp (arg, "summary") == 0)
575 {
576 summary = 1;
577 }
573 else if (strcmp (arg, "backup") == 0) 578 else if (strcmp (arg, "backup") == 0)
574 { 579 {
575 rcvr.errfun = err_printer; 580 rcvr.errfun = err_printer;
576 flags |= GDBM_RCVR_BACKUP; 581 flags |= GDBM_RCVR_BACKUP;
577 } 582 }
578 else if (strncmp (arg, "max-failures=", 13) == 0) 583 else if (strncmp (arg, "max-failures=", 13) == 0)
579 { 584 {
580 rcvr.max_failures = strtoul (arg + 13, &p, 10); 585 rcvr.max_failures = strtoul (arg + 13, &p, 10);
581 if (*p) 586 if (*p)
582 { 587 {
583 printf (_("not a number (stopped near %s)\n"), p); 588 printf (_("not a number (stopped near %s)\n"), p);
584 return; 589 return;
@@ -608,24 +613,37 @@ recover_handler (struct handler_param *param)
608 else 613 else
609 { 614 {
610 terror (_("unrecognized argument: %s"), arg); 615 terror (_("unrecognized argument: %s"), arg);
611 return; 616 return;
612 } 617 }
613 } 618 }
614 619
615 rc = gdbm_recover (gdbm_file, &rcvr, flags); 620 rc = gdbm_recover (gdbm_file, &rcvr, flags);
616 621
617 if (rc == 0) 622 if (rc == 0)
618 { 623 {
619 fprintf (param->fp, _("Recovery succeeded.\n")); 624 fprintf (param->fp, _("Recovery succeeded.\n"));
625 if (summary)
626 {
627 fprintf (param->fp,
628 _("Keys recovered: %lu, failed: %lu, duplicate: %lu\n"),
629 (unsigned long) rcvr.recovered_keys,
630 (unsigned long) rcvr.failed_keys,
631 (unsigned long) rcvr.duplicate_keys);
632 fprintf (param->fp,
633 _("Buckets recovered: %lu, failed: %lu\n"),
634 (unsigned long) rcvr.recovered_buckets,
635 (unsigned long) rcvr.failed_buckets);
636 }
637
620 if (rcvr.backup_name) 638 if (rcvr.backup_name)
621 { 639 {
622 fprintf (param->fp, 640 fprintf (param->fp,
623 _("Original database preserved in file %s"), 641 _("Original database preserved in file %s"),
624 rcvr.backup_name); 642 rcvr.backup_name);
625 free (rcvr.backup_name); 643 free (rcvr.backup_name);
626 } 644 }
627 fputc ('\n', param->fp); 645 fputc ('\n', param->fp);
628 } 646 }
629 else 647 else
630 { 648 {
631 fprintf (stderr, _("Recovery failed: %s"), gdbm_strerror (gdbm_errno)); 649 fprintf (stderr, _("Recovery failed: %s"), gdbm_strerror (gdbm_errno));
@@ -916,25 +934,25 @@ quit_handler (struct handler_param *param GDBM_ARG_UNUSED)
916 exit (EXIT_OK); 934 exit (EXIT_OK);
917} 935}
918 936
919/* export FILE [truncate] - export to a flat file format */ 937/* export FILE [truncate] - export to a flat file format */
920void 938void
921export_handler (struct handler_param *param) 939export_handler (struct handler_param *param)
922{ 940{
923 int format = GDBM_DUMP_FMT_ASCII; 941 int format = GDBM_DUMP_FMT_ASCII;
924 int flags = GDBM_WRCREAT; 942 int flags = GDBM_WRCREAT;
925 int i; 943 int i;
926 int filemode; 944 int filemode;
927 945
928 for (i = 1; i < param->argc; i++) 946 for (i = 0; i < param->argc; i++)
929 { 947 {
930 if (strcmp (PARAM_STRING (param, i), "truncate") == 0) 948 if (strcmp (PARAM_STRING (param, i), "truncate") == 0)
931 flags = GDBM_NEWDB; 949 flags = GDBM_NEWDB;
932 else if (strcmp (PARAM_STRING (param, i), "binary") == 0) 950 else if (strcmp (PARAM_STRING (param, i), "binary") == 0)
933 format = GDBM_DUMP_FMT_BINARY; 951 format = GDBM_DUMP_FMT_BINARY;
934 else if (strcmp (PARAM_STRING (param, i), "ascii") == 0) 952 else if (strcmp (PARAM_STRING (param, i), "ascii") == 0)
935 format = GDBM_DUMP_FMT_ASCII; 953 format = GDBM_DUMP_FMT_ASCII;
936 else 954 else
937 { 955 {
938 terror (_("unrecognized argument: %s"), PARAM_STRING (param, i)); 956 terror (_("unrecognized argument: %s"), PARAM_STRING (param, i));
939 return; 957 return;
940 } 958 }
@@ -950,25 +968,25 @@ export_handler (struct handler_param *param)
950} 968}
951 969
952/* import FILE [replace] [nometa] - import from a flat file */ 970/* import FILE [replace] [nometa] - import from a flat file */
953void 971void
954import_handler (struct handler_param *param) 972import_handler (struct handler_param *param)
955{ 973{
956 int flag = GDBM_INSERT; 974 int flag = GDBM_INSERT;
957 unsigned long err_line; 975 unsigned long err_line;
958 int meta_mask = 0; 976 int meta_mask = 0;
959 int i; 977 int i;
960 int rc; 978 int rc;
961 979
962 for (i = 1; i < param->argc; i++) 980 for (i = 0; i < param->argc; i++)
963 { 981 {
964 if (strcmp (PARAM_STRING (param, i), "replace") == 0) 982 if (strcmp (PARAM_STRING (param, i), "replace") == 0)
965 flag = GDBM_REPLACE; 983 flag = GDBM_REPLACE;
966 else if (strcmp (PARAM_STRING (param, i), "nometa") == 0) 984 else if (strcmp (PARAM_STRING (param, i), "nometa") == 0)
967 meta_mask = GDBM_META_MASK_MODE | GDBM_META_MASK_OWNER; 985 meta_mask = GDBM_META_MASK_MODE | GDBM_META_MASK_OWNER;
968 else 986 else
969 { 987 {
970 terror (_("unrecognized argument: %s"), 988 terror (_("unrecognized argument: %s"),
971 PARAM_STRING (param, i)); 989 PARAM_STRING (param, i));
972 return; 990 return;
973 } 991 }
974 } 992 }
@@ -1211,24 +1229,25 @@ struct command command_tab[] = {
1211 FALSE, 1229 FALSE,
1212 REPEAT_NEVER, 1230 REPEAT_NEVER,
1213 N_("firstkey") }, 1231 N_("firstkey") },
1214 { S(reorganize), T_CMD, 1232 { S(reorganize), T_CMD,
1215 checkdb, reorganize_handler, NULL, 1233 checkdb, reorganize_handler, NULL,
1216 { { NULL } }, 1234 { { NULL } },
1217 FALSE, 1235 FALSE,
1218 REPEAT_NEVER, 1236 REPEAT_NEVER,
1219 N_("reorganize") }, 1237 N_("reorganize") },
1220 { S(recover), T_CMD, 1238 { S(recover), T_CMD,
1221 checkdb, recover_handler, NULL, 1239 checkdb, recover_handler, NULL,
1222 { { "[verbose]", GDBM_ARG_STRING }, 1240 { { "[verbose]", GDBM_ARG_STRING },
1241 { "[summary]", GDBM_ARG_STRING },
1223 { "[backup]", GDBM_ARG_STRING }, 1242 { "[backup]", GDBM_ARG_STRING },
1224 { "[max-failed-keys=N]", GDBM_ARG_STRING }, 1243 { "[max-failed-keys=N]", GDBM_ARG_STRING },
1225 { "[max-failed-buckets=N]", GDBM_ARG_STRING }, 1244 { "[max-failed-buckets=N]", GDBM_ARG_STRING },
1226 { "[max-failures=N]", GDBM_ARG_STRING }, 1245 { "[max-failures=N]", GDBM_ARG_STRING },
1227 { NULL } }, 1246 { NULL } },
1228 FALSE, 1247 FALSE,
1229 REPEAT_NEVER, 1248 REPEAT_NEVER,
1230 N_("recover the database") }, 1249 N_("recover the database") },
1231 { S(avail), T_CMD, 1250 { S(avail), T_CMD,
1232 avail_begin, avail_handler, NULL, 1251 avail_begin, avail_handler, NULL,
1233 { { NULL } }, 1252 { { NULL } },
1234 FALSE, 1253 FALSE,
diff --git a/src/mmap.c b/src/mmap.c
index 114d8b2..24ede29 100644
--- a/src/mmap.c
+++ b/src/mmap.c
@@ -35,26 +35,33 @@
35 35
36/* Translate current offset in the mapped region into the absolute position */ 36/* Translate current offset in the mapped region into the absolute position */
37# define _GDBM_MMAPPED_POS(dbf) ((dbf)->mapped_off + (dbf)->mapped_pos) 37# define _GDBM_MMAPPED_POS(dbf) ((dbf)->mapped_off + (dbf)->mapped_pos)
38/* Return true if the absolute offset OFF lies within the currentlty mmapped 38/* Return true if the absolute offset OFF lies within the currentlty mmapped
39 region */ 39 region */
40# define _GDBM_IN_MAPPED_REGION_P(dbf, off) \ 40# define _GDBM_IN_MAPPED_REGION_P(dbf, off) \
41 ((off) >= (dbf)->mapped_off \ 41 ((off) >= (dbf)->mapped_off \
42 && ((off) - (dbf)->mapped_off) < (dbf)->mapped_size) 42 && ((off) - (dbf)->mapped_off) < (dbf)->mapped_size)
43/* Return true if the current region needs to be remapped */ 43/* Return true if the current region needs to be remapped */
44# define _GDBM_NEED_REMAP(dbf) \ 44# define _GDBM_NEED_REMAP(dbf) \
45 (!(dbf)->mapped_region || (dbf)->mapped_pos == (dbf)->mapped_size) 45 (!(dbf)->mapped_region || (dbf)->mapped_pos == (dbf)->mapped_size)
46/* Return the sum of the currently mapped size and DELTA */ 46/* Return the sum of the currently mapped size and DELTA */
47# define SUM_FILE_SIZE(dbf, delta) \ 47static inline off_t
48 ((dbf)->mapped_off + (dbf)->mapped_size + (delta)) 48SUM_FILE_SIZE (GDBM_FILE dbf, off_t delta)
49{
50 if (delta >= 0
51 && off_t_sum_ok (dbf->mapped_off, dbf->mapped_size)
52 && off_t_sum_ok (dbf->mapped_off + dbf->mapped_size, delta))
53 return dbf->mapped_off + dbf->mapped_size + delta;
54 return -1;
55}
49 56
50/* Store the size of the GDBM file DBF in *PSIZE. 57/* Store the size of the GDBM file DBF in *PSIZE.
51 Return 0 on success and -1 on failure. */ 58 Return 0 on success and -1 on failure. */
52int 59int
53_gdbm_file_size (GDBM_FILE dbf, off_t *psize) 60_gdbm_file_size (GDBM_FILE dbf, off_t *psize)
54{ 61{
55 struct stat sb; 62 struct stat sb;
56 if (fstat (dbf->desc, &sb)) 63 if (fstat (dbf->desc, &sb))
57 { 64 {
58 GDBM_SET_ERRNO (dbf, GDBM_FILE_STAT_ERROR, FALSE); 65 GDBM_SET_ERRNO (dbf, GDBM_FILE_STAT_ERROR, FALSE);
59 return -1; 66 return -1;
60 } 67 }
@@ -173,24 +180,35 @@ _gdbm_file_extend (GDBM_FILE dbf, off_t size)
173 truncated to the actual file size. 180 truncated to the actual file size.
174 181
175 The upper bound obtained that way is used as a *hint* to select 182 The upper bound obtained that way is used as a *hint* to select
176 the actual size of the mapped region. which can never exceed 183 the actual size of the mapped region. which can never exceed
177 dbf->mapped_size_max. 184 dbf->mapped_size_max.
178 185
179 The function returns 0 on success, -1 on failure. */ 186 The function returns 0 on success, -1 on failure. */
180int 187int
181_gdbm_mapped_remap (GDBM_FILE dbf, off_t size, int flag) 188_gdbm_mapped_remap (GDBM_FILE dbf, off_t size, int flag)
182{ 189{
183 off_t file_size, pos; 190 off_t file_size, pos;
184 191
192 if (size < 0)
193 {
194 errno = EINVAL;
195 GDBM_SET_ERRNO (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
196 return -1;
197 }
198
199 if (size < dbf->mapped_size)
200 /* Nothing to do */
201 return 0;
202
185 if (_gdbm_file_size (dbf, &file_size)) 203 if (_gdbm_file_size (dbf, &file_size))
186 { 204 {
187 SAVE_ERRNO (_gdbm_mapped_unmap (dbf)); 205 SAVE_ERRNO (_gdbm_mapped_unmap (dbf));
188 return -1; 206 return -1;
189 } 207 }
190 208
191 if (flag == _REMAP_END && size < file_size) 209 if (flag == _REMAP_END && size < file_size)
192 size = file_size; 210 size = file_size;
193 211
194 if (dbf->read_write) 212 if (dbf->read_write)
195 { 213 {
196 if (size > file_size) 214 if (size > file_size)
diff --git a/src/recover.c b/src/recover.c
index d6d4ff9..721c23f 100644
--- a/src/recover.c
+++ b/src/recover.c
@@ -303,37 +303,52 @@ run_recovery (GDBM_FILE dbf, GDBM_FILE new_dbf, gdbm_recovery *rcvr, int flags)
303 return -1; 303 return -1;
304 continue; 304 continue;
305 } 305 }
306 306
307 key.dptr = dptr; 307 key.dptr = dptr;
308 key.dsize = dbf->bucket->h_table[i].key_size; 308 key.dsize = dbf->bucket->h_table[i].key_size;
309 309
310 data.dptr = dptr + key.dsize; 310 data.dptr = dptr + key.dsize;
311 data.dsize = dbf->bucket->h_table[i].data_size; 311 data.dsize = dbf->bucket->h_table[i].data_size;
312 312
313 if (gdbm_store (new_dbf, key, data, GDBM_INSERT) != 0) 313 if (gdbm_store (new_dbf, key, data, GDBM_INSERT) != 0)
314 { 314 {
315 switch (gdbm_last_errno (new_dbf))
316 {
317 case GDBM_CANNOT_REPLACE:
318 rcvr->duplicate_keys++;
319 if (flags & GDBM_RCVR_ERRFUN)
320 rcvr->errfun (rcvr->data,
321 _("ignoring duplicate key %d:%d (%lu:%d)"),
322 bucket_dir, i,
323 (unsigned long) dbf->bucket->h_table[i].data_pointer,
324 dbf->bucket->h_table[i].key_size
325 + dbf->bucket->h_table[i].data_size);
326 break;
327
328 default:
315 if (flags & GDBM_RCVR_ERRFUN) 329 if (flags & GDBM_RCVR_ERRFUN)
316 rcvr->errfun (rcvr->data, 330 rcvr->errfun (rcvr->data,
317 _("fatal: can't store element %d:%d (%lu:%d): %s"), 331 _("fatal: can't store element %d:%d (%lu:%d): %s"),
318 bucket_dir, i, 332 bucket_dir, i,
319 (unsigned long) dbf->bucket->h_table[i].data_pointer, 333 (unsigned long) dbf->bucket->h_table[i].data_pointer,
320 dbf->bucket->h_table[i].key_size 334 dbf->bucket->h_table[i].key_size
321 + dbf->bucket->h_table[i].data_size, 335 + dbf->bucket->h_table[i].data_size,
322 gdbm_db_strerror (new_dbf)); 336 gdbm_db_strerror (new_dbf));
323 return -1; 337 return -1;
324 } 338 }
325 } 339 }
326 } 340 }
327 } 341 }
342 }
328 343
329 return 0; 344 return 0;
330} 345}
331 346
332int 347int
333gdbm_recover (GDBM_FILE dbf, gdbm_recovery *rcvr, int flags) 348gdbm_recover (GDBM_FILE dbf, gdbm_recovery *rcvr, int flags)
334{ 349{
335 GDBM_FILE new_dbf; /* The new file. */ 350 GDBM_FILE new_dbf; /* The new file. */
336 char *new_name; /* A temporary name. */ 351 char *new_name; /* A temporary name. */
337 size_t len; 352 size_t len;
338 int fd; 353 int fd;
339 int rc; 354 int rc;
@@ -347,24 +362,25 @@ gdbm_recover (GDBM_FILE dbf, gdbm_recovery *rcvr, int flags)
347 } 362 }
348 363
349 /* Initialize gdbm_recovery structure */ 364 /* Initialize gdbm_recovery structure */
350 if (!rcvr) 365 if (!rcvr)
351 { 366 {
352 rcvr = &rs; 367 rcvr = &rs;
353 flags = 0; 368 flags = 0;
354 } 369 }
355 rcvr->recovered_keys = 0; 370 rcvr->recovered_keys = 0;
356 rcvr->recovered_buckets = 0; 371 rcvr->recovered_buckets = 0;
357 rcvr->failed_keys = 0; 372 rcvr->failed_keys = 0;
358 rcvr->failed_buckets = 0; 373 rcvr->failed_buckets = 0;
374 rcvr->duplicate_keys = 0;
359 rcvr->backup_name = NULL; 375 rcvr->backup_name = NULL;
360 376
361 rc = 0; 377 rc = 0;
362 if ((flags & GDBM_RCVR_FORCE) || check_db (dbf)) 378 if ((flags & GDBM_RCVR_FORCE) || check_db (dbf))
363 { 379 {
364 len = strlen (dbf->name); 380 len = strlen (dbf->name);
365 new_name = malloc (len + sizeof (TMPSUF)); 381 new_name = malloc (len + sizeof (TMPSUF));
366 if (!new_name) 382 if (!new_name)
367 { 383 {
368 GDBM_SET_ERRNO (NULL, GDBM_MALLOC_ERROR, FALSE); 384 GDBM_SET_ERRNO (NULL, GDBM_MALLOC_ERROR, FALSE);
369 return -1; 385 return -1;
370 } 386 }
diff --git a/src/systems.h b/src/systems.h
index 66955dd..c678573 100644
--- a/src/systems.h
+++ b/src/systems.h
@@ -24,24 +24,25 @@
24# include <sys/file.h> 24# include <sys/file.h>
25#endif 25#endif
26#include <sys/stat.h> 26#include <sys/stat.h>
27#include <stdlib.h> 27#include <stdlib.h>
28#if HAVE_STRING_H 28#if HAVE_STRING_H
29# include <string.h> 29# include <string.h>
30#else 30#else
31# include <strings.h> 31# include <strings.h>
32#endif 32#endif
33#include <unistd.h> 33#include <unistd.h>
34#include <fcntl.h> 34#include <fcntl.h>
35#include <errno.h> 35#include <errno.h>
36#include <limits.h>
36 37
37#ifndef SEEK_SET 38#ifndef SEEK_SET
38# define SEEK_SET 0 39# define SEEK_SET 0
39#endif 40#endif
40 41
41#ifndef O_CLOEXEC 42#ifndef O_CLOEXEC
42# define O_CLOEXEC 0 43# define O_CLOEXEC 0
43#endif 44#endif
44 45
45/* Default block size. Some systems do not have blocksize in their 46/* Default block size. Some systems do not have blocksize in their
46 stat record. This code uses the BSD blocksize from stat. */ 47 stat record. This code uses the BSD blocksize from stat. */
47 48

Return to:

Send suggestions and report system problems to the System administrator.