aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-11-13 15:28:04 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2011-11-13 15:28:04 +0000
commitfd714cdcec660f915917edd239324e7544daa234 (patch)
tree9bcf5029b60bf482a2d13b7b2a2194b4a6f7c6f5 /src
parent5d14e2acfec6f5ded1c88c7912224157a79be351 (diff)
downloadgdbm-fd714cdcec660f915917edd239324e7544daa234.tar.gz
gdbm-fd714cdcec660f915917edd239324e7544daa234.tar.bz2
Implement new dump format. Add new utilities: gdbm_dump and gdbm_load.
* configure.ac (AC_CHECK_HEADERS): Don't check for files that must always be present. Check for getopt.h. (AC_CHECK_FUNCS): Add getopt_long * src/systems.h: Include useless #if's. * src/flatfile.c: Split into two files: * src/gdbmexp.c: ... this and ... * src/gdbmimp.c: .., this * src/mem.c: New file. * src/base64.c: New file. * src/gdbm_dump.c: New file. * src/gdbm_load.c: New file. * src/gdbmapp.h: New file. * src/gdbmdump.c: New file. * src/gdbmload.c: New file. * src/parseopt.c: New file. * src/progname.c: New file. * src/.cvsignore: Update. * src/Makefile.am (libgdbm_la_SOURCES): Add new files. (noinst_LIBRARIES): New variable. Build libgdbmapp.a. (libgdbmapp_a_SOURCES): New variable. (bin_PROGRAMS): Add gdbm_load and gdbm_dump (testgdbm_LDADD, gdbm_load_LDADD) (gdbm_dump_LDADD): Add ./libgdbmapp.a * src/gdbm.h.in: Include <stdio.h> (gdbm_export_to_file) (gdbm_import_from_file): New prototypes. (GDBM_DUMP_FMT_BINARY,GDBM_DUMP_FMT_ASCII): New constants. (gdbm_dump,gdbm_load) (gdbm_dump_to_file,gdbm_load_from_file): New prototypes. (GDBM_NO_DBNAME): New error code. (_GDBM_MAX_ERRNO): Update. * src/gdbmdefs.h (_GDBM_MAX_DUMP_LINE_LEN): New constant. * src/gdbmerrno.c (gdbm_errlist): Add entry for GDBM_NO_DBNAME. * src/proto.h (_gdbm_base64_encode,_gdbm_base64_decode) (_gdbm_load,_gdbm_dump): New prototypes. * src/testgdbm.c: Use gdbmapp interface for option parsing. * export/export.c: Include gdbmexp.c * export/.cvsignore: Update. * doc/gdbm.texinfo: Update.
Diffstat (limited to 'src')
-rw-r--r--src/.cvsignore2
-rw-r--r--src/Makefile.am35
-rw-r--r--src/base64.c127
-rw-r--r--src/flatfile.c246
-rw-r--r--src/gdbm.h.in23
-rw-r--r--src/gdbm_dump.c124
-rw-r--r--src/gdbm_load.c140
-rw-r--r--src/gdbmapp.h52
-rw-r--r--src/gdbmdefs.h2
-rw-r--r--src/gdbmdump.c193
-rw-r--r--src/gdbmerrno.c1
-rw-r--r--src/gdbmexp.c125
-rw-r--r--src/gdbmimp.c157
-rw-r--r--src/gdbmload.c502
-rw-r--r--src/mem.c74
-rw-r--r--src/parseopt.c585
-rw-r--r--src/progname.c35
-rw-r--r--src/proto.h12
-rw-r--r--src/systems.h16
-rw-r--r--src/testgdbm.c142
20 files changed, 2233 insertions, 360 deletions
diff --git a/src/.cvsignore b/src/.cvsignore
index ee2dbd5..46838d7 100644
--- a/src/.cvsignore
+++ b/src/.cvsignore
@@ -7,3 +7,5 @@ gdbm.h
*.lo
libgdbm.la
testgdbm
+gdbm_dump
+gdbm_load
diff --git a/src/Makefile.am b/src/Makefile.am
index 1c55a4e..2d7a81a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,22 +37,26 @@ lib_LTLIBRARIES = libgdbm.la
libgdbm_la_LIBADD = @LTLIBINTL@
libgdbm_la_SOURCES = \
- gdbmopen.c\
- gdbmdelete.c\
- gdbmfetch.c\
- gdbmstore.c\
gdbmclose.c\
- gdbmreorg.c\
- gdbmseq.c\
- gdbmsync.c\
+ gdbmdelete.c\
+ gdbmdump.c\
gdbmerrno.c\
gdbmexists.c\
+ gdbmexp.c\
gdbmfdesc.c\
+ gdbmfetch.c\
+ gdbmload.c\
+ gdbmopen.c\
+ gdbmimp.c\
+ gdbmreorg.c\
+ gdbmseq.c\
gdbmsetopt.c\
+ gdbmstore.c\
+ gdbmsync.c\
+ base64.c\
bucket.c\
falloc.c\
findkey.c\
- flatfile.c\
fullio.c\
hash.c\
lock.c\
@@ -62,6 +66,17 @@ libgdbm_la_SOURCES = \
libgdbm_la_LDFLAGS = -version-info $(VI_CURRENT):$(VI_REVISION):$(VI_AGE)
+noinst_LIBRARIES = libgdbmapp.a
+
+libgdbmapp_a_SOURCES =\
+ err.c\
+ mem.c\
+ gdbmapp.h\
+ parseopt.c\
+ progname.c
+
# Programs
-bin_PROGRAMS = testgdbm
-testgdbm_LDADD = ./libgdbm.la
+bin_PROGRAMS = testgdbm gdbm_load gdbm_dump
+testgdbm_LDADD = ./libgdbmapp.a ./libgdbm.la
+gdbm_load_LDADD = ./libgdbmapp.a ./libgdbm.la
+gdbm_dump_LDADD = ./libgdbmapp.a ./libgdbm.la
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 0000000..bf2bf6a
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,127 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ GDBM is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GDBM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+# include "autoconf.h"
+# include "gdbmdefs.h"
+# include "gdbm.h"
+
+static char b64tab[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static int b64val[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
+};
+
+int
+_gdbm_base64_encode (const unsigned char *input, size_t input_len,
+ unsigned char **output, size_t *output_size,
+ size_t *nbytes)
+{
+ size_t olen = 4 * (input_len + 2) / 3 + 1;
+ unsigned char *out;
+
+ if (olen > *output_size)
+ {
+ out = realloc (*output, olen);
+ if (!out)
+ return GDBM_MALLOC_ERROR;
+ *output = out;
+ *output_size = olen;
+ }
+ else
+ out = *output;
+
+ while (input_len >= 3)
+ {
+ *out++ = b64tab[input[0] >> 2];
+ *out++ = b64tab[((input[0] << 4) & 0x30) | (input[1] >> 4)];
+ *out++ = b64tab[((input[1] << 2) & 0x3c) | (input[2] >> 6)];
+ *out++ = b64tab[input[2] & 0x3f];
+ input_len -= 3;
+ input += 3;
+ }
+
+ if (input_len > 0)
+ {
+ unsigned char c = (input[0] << 4) & 0x30;
+ *out++ = b64tab[input[0] >> 2];
+ if (input_len > 1)
+ c |= input[1] >> 4;
+ *out++ = b64tab[c];
+ *out++ = (input_len < 2) ? '=' : b64tab[(input[1] << 2) & 0x3c];
+ *out++ = '=';
+ }
+ *out = 0;
+ *nbytes = out - *output;
+ return 0;
+}
+
+int
+_gdbm_base64_decode (const unsigned char *input, size_t input_len,
+ unsigned char **output, size_t *output_size,
+ size_t *inbytes, size_t *outbytes)
+{
+ int rc = 0;
+ int olen = input_len;
+ unsigned char *out;
+ size_t ins = 0;
+
+ if (olen > *output_size)
+ {
+ out = realloc (*output, olen);
+ if (!out)
+ return GDBM_MALLOC_ERROR;
+ *output = out;
+ *output_size = olen;
+ }
+ else
+ out = *output;
+
+ do
+ {
+ if (input_len < 4)
+ break;
+ if (input[0] > 127 || b64val[input[0]] == -1
+ || input[1] > 127 || b64val[input[1]] == -1
+ || input[2] > 127 || ((input[2] != '=') && (b64val[input[2]] == -1))
+ || input[3] > 127 || ((input[3] != '=')
+ && (b64val[input[3]] == -1)))
+ {
+ rc = GDBM_ILLEGAL_DATA;
+ break;
+ }
+ *out++ = (b64val[input[0]] << 2) | (b64val[input[1]] >> 4);
+ if (input[2] != '=')
+ {
+ *out++ = ((b64val[input[1]] << 4) & 0xf0) | (b64val[input[2]] >> 2);
+ if (input[3] != '=')
+ *out++ = ((b64val[input[2]] << 6) & 0xc0) | b64val[input[3]];
+ }
+ input += 4;
+ input_len -= 4;
+ ins += 4;
+ }
+ while (input_len > 0);
+ *inbytes = ins;
+ *outbytes = out - *output;
+ return rc;
+}
diff --git a/src/flatfile.c b/src/flatfile.c
deleted file mode 100644
index c0f9422..0000000
--- a/src/flatfile.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/* flatfile.c - Import/export a GDBM database. */
-
-/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2007, 2011 Free Software Foundation, Inc.
-
- GDBM is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- GDBM is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef _GDBMEXPORT_
-
-/* Include system configuration before all else. */
-# include "autoconf.h"
-# include <arpa/inet.h>
-
-# include "gdbmdefs.h"
-# include "gdbm.h"
-
-#endif
-
-int
-gdbm_export (GDBM_FILE dbf, const char *exportfile, int flags, int mode)
-{
- int nfd, size;
- datum key, nextkey, data;
- const char *header1 = "!\r\n! GDBM FLAT FILE DUMP -- THIS IS NOT A TEXT FILE\r\n! ";
- const char *header2 = "\r\n!\r\n";
- int count = 0;
-
- /* Only support GDBM_WCREAT or GDBM_NEWDB */
- switch (flags)
- {
- case GDBM_WRCREAT:
- nfd = open (exportfile, O_WRONLY | O_CREAT | O_EXCL, mode);
- if (nfd == -1)
- {
- gdbm_errno = GDBM_FILE_OPEN_ERROR;
- return -1;
- }
- break;
- case GDBM_NEWDB:
- nfd = open (exportfile, O_WRONLY | O_CREAT | O_TRUNC, mode);
- if (nfd == -1)
- {
- gdbm_errno = GDBM_FILE_OPEN_ERROR;
- return -1;
- }
- break;
- default:
-#ifdef GDBM_BAD_OPEN_FLAGS
- gdbm_errno = GDBM_BAD_OPEN_FLAGS;
-#else
- gdbm_errno = GDBM_FILE_OPEN_ERROR;
-#endif
- return -1;
- }
-
- /* Write out the text header. */
- if (write (nfd, header1, strlen (header1)) != strlen (header1))
- goto write_fail;
- if (write (nfd, gdbm_version, strlen (gdbm_version)) != strlen (gdbm_version))
- goto write_fail;
- if (write (nfd, header2, strlen (header2)) != strlen (header2))
- goto write_fail;
-
- /* For each item in the database, write out a record to the file. */
- key = gdbm_firstkey (dbf);
-
- while (key.dptr != NULL)
- {
- data = gdbm_fetch (dbf, key);
- if (data.dptr != NULL)
- {
- /* Add the data to the new file. */
- size = htonl (key.dsize);
- if (write (nfd, &size, sizeof(int)) != sizeof (int))
- goto write_fail;
- if (write (nfd, key.dptr, key.dsize) != key.dsize)
- goto write_fail;
-
- size = htonl (data.dsize);
- if (write (nfd, &size, sizeof(int)) != sizeof (int))
- goto write_fail;
- if (write (nfd, data.dptr, data.dsize) != data.dsize)
- goto write_fail;
- }
- nextkey = gdbm_nextkey (dbf, key);
- free (key.dptr);
- free (data.dptr);
- key = nextkey;
-
- count++;
- }
- close (nfd);
-
- return count;
-
- write_fail:
-
- gdbm_errno = GDBM_FILE_WRITE_ERROR;
- return -1;
-}
-
-#ifndef _GDBMEXPORT_
-
-int
-gdbm_import (GDBM_FILE dbf, const char *importfile, int flag)
-{
- int ifd, seenbang, seennewline, rsize, size, kbufsize, dbufsize, rret;
- char c, *kbuffer, *dbuffer;
- datum key, data;
- int count = 0;
-
- ifd = open (importfile, O_RDONLY, 0);
- if (ifd == -1)
- {
- gdbm_errno = GDBM_FILE_OPEN_ERROR;
- return -1;
- }
-
- seenbang = 0;
- seennewline = 0;
- kbuffer = NULL;
- dbuffer = NULL;
-
- /* Read (and discard) four lines begining with ! and ending with \n. */
- while (1)
- {
- if (read (ifd, &c, 1) != 1)
- goto read_fail;
-
- if (c == '!')
- seenbang++;
- if (c == '\n')
- {
- if (seenbang > 3 && seennewline > 2)
- {
- /* End of last line. */
- break;
- }
- seennewline++;
- }
- }
-
- /* Allocate buffers. */
- kbufsize = 512;
- kbuffer = malloc (kbufsize);
- if (kbuffer == NULL)
- {
- gdbm_errno = GDBM_MALLOC_ERROR;
- close (ifd);
- return -1;
- }
- dbufsize = 512;
- dbuffer = malloc (dbufsize);
- if (dbuffer == NULL)
- {
- gdbm_errno = GDBM_MALLOC_ERROR;
- close (ifd);
- return -1;
- }
-
- /* Insert/replace records in the database until we run out of file. */
- while ((rret = read (ifd, &rsize, sizeof(rsize))) != 0)
- {
- if (rret != sizeof(rsize))
- goto read_fail;
-
- /* Read the key. */
- size = ntohl (rsize);
- if (size > kbufsize)
- {
- kbufsize = (size + 512);
- kbuffer = realloc (kbuffer, kbufsize);
- if (kbuffer == NULL)
- {
- gdbm_errno = GDBM_MALLOC_ERROR;
- close (ifd);
- return -1;
- }
- }
- if (read (ifd, kbuffer, size) != size)
- goto read_fail;
-
- key.dptr = kbuffer;
- key.dsize = size;
-
- /* Read the data. */
- if (read (ifd, &rsize, sizeof(rsize)) != sizeof(rsize))
- goto read_fail;
-
- size = ntohl (rsize);
- if (size > dbufsize)
- {
- dbufsize = (size + 512);
- dbuffer = realloc (dbuffer, dbufsize);
- if (dbuffer == NULL)
- {
- gdbm_errno = GDBM_MALLOC_ERROR;
- close (ifd);
- return -1;
- }
- }
- if (read (ifd, dbuffer, size) != size)
- goto read_fail;
-
- data.dptr = dbuffer;
- data.dsize = size;
-
- if (gdbm_store (dbf, key, data, flag) != 0)
- {
- /* Keep the existing errno. */
- free (kbuffer);
- free (dbuffer);
- close (ifd);
- return -1;
- }
-
- count++;
- }
-
- close (ifd);
- return count;
-
-read_fail:
-
- if (kbuffer != NULL)
- free (kbuffer);
- if (dbuffer != NULL)
- free (dbuffer);
-
- close (ifd);
-
- gdbm_errno = GDBM_FILE_READ_ERROR;
- return -1;
-}
-#endif
diff --git a/src/gdbm.h.in b/src/gdbm.h.in
index 21168de..81e9943 100644
--- a/src/gdbm.h.in
+++ b/src/gdbm.h.in
@@ -29,6 +29,8 @@
#ifndef _GDBM_H_
# define _GDBM_H_
+# include <stdio.h>
+
/* GDBM C++ support */
# if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
@@ -111,8 +113,24 @@ extern void gdbm_sync (GDBM_FILE);
extern int gdbm_exists (GDBM_FILE, datum);
extern int gdbm_setopt (GDBM_FILE, int, void *, int);
extern int gdbm_fdesc (GDBM_FILE);
+
extern int gdbm_export (GDBM_FILE, const char *, int, int);
+extern int gdbm_export_to_file (GDBM_FILE dbf, FILE *fp);
+
extern int gdbm_import (GDBM_FILE, const char *, int);
+extern int gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag);
+
+#define GDBM_DUMP_FMT_BINARY 0
+#define GDBM_DUMP_FMT_ASCII 1
+
+extern int gdbm_dump (GDBM_FILE, const char *, int fmt, int open_flags,
+ int mode);
+extern int gdbm_dump_to_file (GDBM_FILE, FILE *, int fmt);
+
+extern int gdbm_load (GDBM_FILE *, const char *, int replace,
+ unsigned long *line);
+extern int gdbm_load_from_file (GDBM_FILE *, FILE *, int replace,
+ unsigned long *line);
# define GDBM_NO_ERROR 0
# define GDBM_MALLOC_ERROR 1
@@ -140,9 +158,10 @@ extern int gdbm_import (GDBM_FILE, const char *, int);
# define GDBM_BAD_OPEN_FLAGS 23
# define GDBM_FILE_STAT_ERROR 24
# define GDBM_FILE_EOF 25
-
+# define GDBM_NO_DBNAME 26
+
# define _GDBM_MIN_ERRNO 0
-# define _GDBM_MAX_ERRNO GDBM_FILE_EOF
+# define _GDBM_MAX_ERRNO GDBM_NO_DBNAME
typedef int gdbm_error; /* For compatibilities sake. */
extern gdbm_error gdbm_errno;
extern const char * const gdbm_errlist[];
diff --git a/src/gdbm_dump.c b/src/gdbm_dump.c
new file mode 100644
index 0000000..6ea94e6
--- /dev/null
+++ b/src/gdbm_dump.c
@@ -0,0 +1,124 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ GDBM is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GDBM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+# include "autoconf.h"
+# include "gdbm.h"
+# include "gdbmapp.h"
+# include "gdbmdefs.h"
+
+char *parseopt_program_doc = "dump a GDBM database to a file";
+char *parseopt_program_args = "DB_FILE [FILE]";
+struct gdbm_option optab[] = {
+ { 'H', "format", N_("0|1"), N_("select dump format") },
+ { 'b', "binary", NULL, N_("use binary output format") },
+ { 0 }
+};
+
+int format = GDBM_DUMP_FMT_ASCII;
+
+int
+main (int argc, char **argv)
+{
+ GDBM_FILE dbf;
+ int rc, opt;
+ char *dbname, *filename;
+ FILE *fp;
+
+ set_progname (argv[0]);
+
+ for (opt = parseopt_first (argc, argv, optab);
+ opt != EOF;
+ opt = parseopt_next ())
+ {
+ switch (opt)
+ {
+ case 'b':
+ format = GDBM_DUMP_FMT_BINARY;
+ break;
+
+ case 'H':
+ format = atoi (optarg);
+ switch (format)
+ {
+ case GDBM_DUMP_FMT_BINARY:
+ case GDBM_DUMP_FMT_ASCII:
+ break;
+ default:
+ error (_("unknown dump format"));
+ exit (2);
+ }
+ break;
+
+ default:
+ error (_("unknown option"));
+ exit (2);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ {
+ parseopt_print_help ();
+ exit (0);
+ }
+
+ if (argc > 2)
+ {
+ error (_("too many arguments; try `%s -h' for more info"), progname);
+ exit (2);
+ }
+
+ dbname = argv[0];
+ if (argc == 2)
+ filename = argv[1];
+ else
+ filename = NULL;
+
+ if (!filename || strcmp (filename, "-") == 0)
+ {
+ filename = "<stdout>";
+ fp = stdout;
+ }
+ else
+ {
+ fp = fopen (filename, "w");
+ if (!fp)
+ {
+ sys_perror (errno, _("cannot open %s"), filename);
+ exit (1);
+ }
+ }
+
+ dbf = gdbm_open (dbname, 0, GDBM_READER, 0600, NULL);
+ if (!dbf)
+ {
+ gdbm_perror (_("gdbm_open failed"));
+ exit (1);
+ }
+
+ rc = gdbm_dump_to_file (dbf, fp, format);
+ if (rc)
+ {
+ gdbm_perror (_("dump error"), filename);
+ }
+
+ gdbm_close (dbf);
+
+ exit (!!rc);
+}
+
diff --git a/src/gdbm_load.c b/src/gdbm_load.c
new file mode 100644
index 0000000..4e14207
--- /dev/null
+++ b/src/gdbm_load.c
@@ -0,0 +1,140 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ GDBM is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GDBM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+# include "autoconf.h"
+# include "gdbm.h"
+# include "gdbmapp.h"
+# include "gdbmdefs.h"
+
+/* usage: gdbm_load [OPTIONS] FILE [DB_FILE]
+ FILE is either "-" or a file name.
+ OPTIONS are:
+ -h, --help
+ -u, --usage
+ -v, --version
+
+ -p, --permissions OOO
+ -u, --user NAME-OR-UID
+ -g, --group NAME-OR-GID
+*/
+
+int replace = 0;
+
+char *parseopt_program_doc = "load a GDBM database from a file";
+char *parseopt_program_args = "FILE [DB_FILE]";
+struct gdbm_option optab[] = {
+ { 'r', "replace", NULL, N_("replace records in the existing database") },
+ { 0 }
+};
+
+int
+main (int argc, char **argv)
+{
+ GDBM_FILE dbf = NULL;
+ int rc, opt;
+ char *dbname, *filename;
+ FILE *fp;
+ unsigned long err_line;
+
+ set_progname (argv[0]);
+
+ for (opt = parseopt_first (argc, argv, optab);
+ opt != EOF;
+ opt = parseopt_next ())
+ {
+ switch (opt)
+ {
+ case 'r':
+ replace = 1;
+ break;
+
+ default:
+ error (_("unknown option"));
+ exit (2);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ {
+ parseopt_print_help ();
+ exit (0);
+ }
+
+ if (argc > 2)
+ {
+ error (_("too many arguments; try `%s -h' for more info"), progname);
+ exit (2);
+ }
+
+ filename = argv[0];
+ if (argc == 2)
+ dbname = argv[1];
+ else
+ dbname = NULL;
+
+ if (strcmp (filename, "-") == 0)
+ {
+ filename = "<stdin>";
+ fp = stdin;
+ }
+ else
+ {
+ fp = fopen (filename, "r");
+ if (!fp)
+ {
+ sys_perror (errno, _("cannot open %s"), filename);
+ exit (1);
+ }
+ }
+
+ if (dbname)
+ {
+ dbf = gdbm_open (dbname, 0, GDBM_NEWDB, 0600, NULL);
+ if (!dbf)
+ {
+ gdbm_perror (_("gdbm_open failed"));
+ exit (1);
+ }
+ }
+
+ rc = gdbm_load_from_file (&dbf, fp, replace, &err_line);
+ if (rc)
+ {
+ if (err_line)
+ gdbm_perror ("%s:%lu", filename, err_line);
+ else
+ gdbm_perror ("cannot load from %s", filename);
+ }
+
+ if (dbf)
+ {
+ if (!dbname)
+ {
+ if (gdbm_setopt (dbf, GDBM_GETDBNAME, &dbname, sizeof (dbname)))
+ gdbm_perror (_("gdbm_setopt failed"));
+ else
+ {
+ printf ("%s: created %s\n", progname, dbname);
+ free (dbname);
+ }
+ }
+ gdbm_close (dbf);
+ }
+ exit (!!rc);
+}
diff --git a/src/gdbmapp.h b/src/gdbmapp.h
new file mode 100644
index 0000000..e7917f9
--- /dev/null
+++ b/src/gdbmapp.h
@@ -0,0 +1,52 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ GDBM is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GDBM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+extern const char *progname;
+
+void set_progname (const char *arg);
+void gdbm_perror (const char *fmt, ...);
+void sys_perror (int code, const char *fmt, ...);
+void error (const char *fmt, ...);
+void verror (const char *fmt, va_list ap);
+
+void *emalloc (size_t size);
+void *erealloc (void *ptr, size_t size);
+void *ecalloc (size_t nmemb, size_t size);
+void *ezalloc (size_t size);
+char *estrdup (char *str);
+
+#define PARSEOPT_HIDDEN 0x01
+#define PARSEOPT_ALIAS 0x02
+
+struct gdbm_option
+{
+ int opt_short;
+ char *opt_long;
+ char *opt_arg;
+ char *opt_descr;
+ int opt_flags;
+};
+
+int parseopt_first (int pc, char **pv, struct gdbm_option *options);
+int parseopt_next (void);
+void parseopt_print_help (void);
+
+extern char *parseopt_program_name;
+extern char *parseopt_program_doc;
+extern char *parseopt_program_args;
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index 519d688..4ebb190 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -217,5 +217,7 @@ struct gdbm_file_info {
} \
while (0) \
+#define _GDBM_MAX_DUMP_LINE_LEN 76
+
/* Now define all the routines in use. */
#include "proto.h"
diff --git a/src/gdbmdump.c b/src/gdbmdump.c
new file mode 100644
index 0000000..9380931
--- /dev/null
+++ b/src/gdbmdump.c
@@ -0,0 +1,193 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ GDBM is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GDBM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+# include "autoconf.h"
+# include "gdbmdefs.h"
+# include "gdbm.h"
+# include <pwd.h>
+# include <grp.h>
+# include <time.h>
+
+static int
+print_datum (datum const *dat, unsigned char **bufptr,
+ size_t *bufsize, FILE *fp)
+{
+ int rc;
+ size_t len;
+ unsigned char *p;
+
+ fprintf (fp, "#:len=%lu\n", (unsigned long) dat->dsize);
+ rc = _gdbm_base64_encode ((unsigned char*) dat->dptr, dat->dsize,
+ bufptr, bufsize, &len);
+ if (rc)
+ return rc;
+
+ p = *bufptr;
+ while (len)
+ {
+ size_t n = len;
+ if (n > _GDBM_MAX_DUMP_LINE_LEN)
+ n = _GDBM_MAX_DUMP_LINE_LEN;
+ if (fwrite (p, n, 1, fp) != 1)
+ return GDBM_FILE_WRITE_ERROR;
+ fputc ('\n', fp);
+ len -= n;
+ p += n;
+ }
+ return 0;
+}
+
+int
+_gdbm_dump_ascii (GDBM_FILE dbf, FILE *fp)
+{
+ time_t t;
+ int fd;
+ struct stat st;
+ struct passwd *pw;
+ struct group *gr;
+ datum key;
+ size_t count = 0;
+ unsigned char *buffer = NULL;
+ size_t bufsize = 0;
+ int rc;
+
+ fd = gdbm_fdesc (dbf);
+ if (fstat (fd, &st))
+ return GDBM_FILE_STAT_ERROR;
+
+ /* Print header */
+ time (&t);
+ fprintf (fp, "# GDBM dump file created by %s on %s",
+ gdbm_version, ctime (&t));
+ fprintf (fp, "#:version=1.0\n");
+
+ fprintf (fp, "#:file=%s\n", dbf->name);
+ fprintf (fp, "#:uid=%lu,", (unsigned long) st.st_uid);
+ pw = getpwuid (st.st_uid);
+ if (pw)
+ fprintf (fp, "user=%s,", pw->pw_name);
+ fprintf (fp, "gid=%lu,", (unsigned long) st.st_gid);
+ gr = getgrgid (st.st_gid);
+ if (gr)
+ fprintf (fp, "group=%s,", gr->gr_name);
+ fprintf (fp, "mode=%03o\n", st.st_mode & 0777);
+ fprintf (fp, "# End of header\n");
+
+ key = gdbm_firstkey (dbf);
+
+ while (key.dptr)
+ {
+ datum nextkey;
+ datum data = gdbm_fetch (dbf, key);
+ if (data.dptr)
+ {
+ if ((rc = print_datum (&key, &buffer, &bufsize, fp)) ||
+ (rc = print_datum (&data, &buffer, &bufsize, fp)))
+ {
+ free (key.dptr);
+ free (data.dptr);
+ gdbm_errno = rc;
+ break;
+ }
+ }
+ nextkey = gdbm_nextkey (dbf, key);
+ free (key.dptr);
+ free (data.dptr);
+ key = nextkey;
+ count++;
+ }
+
+ if (rc == 0)
+ {
+ /* FIXME: Something like that won't hurt, although load does not
+ use it currently. */
+ fprintf (fp, "#:count=%lu\n", (unsigned long) count);
+ fprintf (fp, "# End of data\n");
+ }
+ free (buffer);
+
+ if (ferror(fp))
+ rc = gdbm_errno = GDBM_FILE_WRITE_ERROR;
+
+ return rc ? -1 : 0;
+}
+
+int
+gdbm_dump_to_file (GDBM_FILE dbf, FILE *fp, int format)
+{
+ int rc;
+
+ switch (format)
+ {
+ case GDBM_DUMP_FMT_BINARY:
+ rc = gdbm_export_to_file (dbf, fp) == -1;
+ break;
+
+ case GDBM_DUMP_FMT_ASCII:
+ rc = _gdbm_dump_ascii (dbf, fp);
+ break;
+
+ default:
+ return EINVAL;
+ }
+ return rc;
+}
+
+int
+gdbm_dump (GDBM_FILE dbf, const char *filename, int fmt, int open_flags,
+ int mode)
+{
+ int nfd, rc;
+ FILE *fp;
+
+ /* Only support GDBM_WCREAT or GDBM_NEWDB */
+ switch (open_flags)
+ {
+ case GDBM_WRCREAT:
+ nfd = open (filename, O_WRONLY | O_CREAT | O_EXCL, mode);
+ if (nfd == -1)
+ {
+ gdbm_errno = GDBM_FILE_OPEN_ERROR;
+ return -1;
+ }
+ break;
+ case GDBM_NEWDB:
+ nfd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ if (nfd == -1)
+ {
+ gdbm_errno = GDBM_FILE_OPEN_ERROR;
+ return -1;
+ }
+ break;
+ default:
+ gdbm_errno = GDBM_BAD_OPEN_FLAGS;
+ return -1;
+ }
+
+ fp = fdopen (nfd, "w");
+ if (!fp)
+ {
+ close (nfd);
+ gdbm_errno = GDBM_FILE_OPEN_ERROR;
+ return -1;
+ }
+ rc = gdbm_dump_to_file (dbf, fp, fmt);
+ fclose (fp);
+ return rc;
+}
+
+
+
diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c
index d9c5c3f..de1aab7 100644
--- a/src/gdbmerrno.c
+++ b/src/gdbmerrno.c
@@ -54,6 +54,7 @@ const char * const gdbm_errlist[_GDBM_MAX_ERRNO+1] = {