/*
* A tool to traverse a corrupted GDBM database, look for special tags, and
* rebuild a consistent database
*/
#include "autoconf.h"
#include "config.h"
#include "db.h"
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <string.h>
#include "gdbm-1.8.0/gdbmdefs.h"
static gdbm_file_info *dbp = NULL;
static void gdbm_panic(mesg)
char *mesg;
{
fprintf(stderr, "GDBM panic: %s\n", mesg);
}
extern char *optarg;
extern int optind;
int main(argc, argv)
int argc;
char *argv[];
{
datum key, dat;
FILE *f;
int numbytes, filesize;
long filepos;
struct stat buf;
bucket_element be;
int c;
char cp;
char *infile, *outfile;
int errflg = 0;
/* Parse options */
infile = outfile = NULL;
while ((c = getopt(argc, argv, "i:o:")) != -1) {
switch (c) {
case 'i':
infile = optarg;
break;
case 'o':
outfile = optarg;
break;
default:
errflg++;
}
}
if (errflg || !infile || !outfile) {
fprintf(stderr, "Usage: %s -i input_file -o output_file\n",
argv[0]);
exit(1);
}
/* Open files */
if ((dbp = gdbm_open(outfile, 8192, GDBM_WRCREAT, 0600,
gdbm_panic)) == NULL) {
fprintf(stderr, "Fatal error in gdbm_open (%s): %s\n",
outfile, strerror(errno));
exit(1);
}
if (stat(infile, &buf)) {
fprintf(stderr, "Fatal error in stat (%s): %s\n",
infile, strerror(errno));
exit(1);
}
filesize = buf.st_size;
f = fopen(infile, "r");
while (fread((void *)&cp, 1, 1, f) != 0) {
/* Quick and dirty */
if (cp == 'T') {
filepos = ftell(f);
/* Rewind one byte */
fseek(f, -1, SEEK_CUR);
if (fread((void *)&be, sizeof(bucket_element),
1, f) == 0) {
fprintf(stderr,
"Fatal error at file position %ld.\n",
filepos);
exit(1);
}
/* Check the tag to make sure it's correct, and
* make sure the pointer and sizes are sane */
if (!memcmp((void *)(be.start_tag),
(void *)"TM3S", 4) &&
be.data_pointer < filesize &&
be.key_size < filesize &&
be.data_size < filesize) {
filepos = ftell(f);
/* Seek to where the data begins */
fseek(f, be.data_pointer, SEEK_SET);
key.dptr = (char *)malloc(be.key_size);
key.dsize = be.key_size;
dat.dptr = (char *)malloc(be.data_size);
dat.dsize = be.data_size;
if ((numbytes = fread((void *)(key.dptr), 1,
key.dsize, f)) == 0) {
fprintf(stderr,
"Fatal error at file position %ld.\n",
filepos);
exit(1);
}
if (fread((void *)(dat.dptr), dat.dsize,
1, f) == 0) {
fprintf(stderr,
"Fatal error at file position %ld.\n",
filepos);
exit(1);
}
if (gdbm_store(dbp, key, dat, GDBM_REPLACE)) {
fprintf(stderr,
"Fatal error in gdbm_store (%s): %s\n",
outfile, strerror(errno));
exit(1);
}
free(key.dptr);
free(dat.dptr);
/* Seek back to where we left off */
fseek(f, filepos, SEEK_SET);
} else {
/* Seek back to one byte after we started
* and continue */
fseek(f, filepos, SEEK_SET);
}
}
}
fclose(f);
gdbm_close(dbp);
exit(0);
}