tinymush-3.1p1/game/backups/
tinymush-3.1p1/game/bin/
tinymush-3.1p1/game/data/
tinymush-3.1p1/game/modules/
tinymush-3.1p1/game/modules/old/
tinymush-3.1p1/src/modules/comsys/
tinymush-3.1p1/src/modules/hello/
tinymush-3.1p1/src/modules/mail/
tinymush-3.1p1/src/tools/
/*
 * 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);
}