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/
/* udb_ochunk.c */
/* $Id: udb_ochunk.c,v 1.53 2002/05/22 19:29:17 dpassmor Exp $ */

/*
 * Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
 */

#include "copyright.h"
#include "autoconf.h"
#include "config.h"

#include "alloc.h"	/* required by mudconf */
#include "flags.h"	/* required by mudconf */
#include "htab.h"	/* required by mudconf */
#include "mudconf.h"	/* required by code */

#include "db.h"		/* required by externs */
#include "externs.h"	/* required by code */

#include "gdbm.h"	/* required by code */
#include "udb.h"	/* required by code */

#define DEFAULT_DBMCHUNKFILE "mudDB"

static char *dbfile = DEFAULT_DBMCHUNKFILE;
static int db_initted = 0;

static GDBM_FILE dbp = (GDBM_FILE) 0;

static datum dat;
static datum key;
static struct flock fl;

extern void VDECL(fatal, (char *, ...));
extern void VDECL(logf, (char *, ...));
extern void FDECL(log_db_err, (int, int, const char *));

void dddb_setsync(flag)
int flag;
{
	char *gdbm_error;
	
	if (gdbm_setopt(dbp, GDBM_SYNCMODE, &flag, sizeof(int)) == -1) {
		gdbm_error = (char *)gdbm_strerror(gdbm_errno);
		logf("setsync: cannot toggle sync flag", dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0);
	}
}

static void dbm_error(msg)
char *msg;
{
	STARTLOG(LOG_ALWAYS, "DB", "ERROR")
		log_printf("Database error: %s\n", msg);
	ENDLOG
}

/* gdbm_reorganize compresses unused space in the db */

int dddb_optimize()
{
	int i;

	i = gdbm_reorganize(dbp);
	return i;
}

int dddb_init()
{
	static char *copen = "db_init cannot open ";
	char tmpfile[256];
	char *gdbm_error;
	int i;
	
	if (!mudstate.standalone)
		sprintf(tmpfile, "%s/%s", mudconf.dbhome, dbfile);
	else
		strcpy(tmpfile, dbfile);
 
	if ((dbp = gdbm_open(tmpfile, mudstate.db_block_size, GDBM_WRCREAT|GDBM_SYNC|GDBM_NOLOCK, 0600, dbm_error)) == (GDBM_FILE) 0) {
		gdbm_error = (char *)gdbm_strerror(gdbm_errno);
		logf(copen, tmpfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0);
		return (1);
	}
	

	if (mudstate.standalone) {
		/* Set the cache size to be 400 hash buckets for GDBM. */

		i = 400;
		if (gdbm_setopt(dbp, GDBM_CACHESIZE, &i, sizeof(int)) == -1) {
			gdbm_error = (char *)gdbm_strerror(gdbm_errno);
			logf(copen, dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0);
			return (1);
		}
	} else {
		/* This would set the cache size to be 2 hash buckets
		 * for GDBM, except that the library imposes a minimum
		 * of 10.
		 */

		i = 2;
		if (gdbm_setopt(dbp, GDBM_CACHESIZE, &i, sizeof(int)) == -1) {
			gdbm_error = (char *)gdbm_strerror(gdbm_errno);
			logf(copen, dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0);
			return (1);
		}
	}
	
	/* Set GDBM to manage a global free space table. */
	 
	i = 1;
	if (gdbm_setopt(dbp, GDBM_CENTFREE, &i, sizeof(int)) == -1) {
		gdbm_error = (char *)gdbm_strerror(gdbm_errno);
		logf(copen, dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0);
		return (1);
	}

	/* Set GDBM to coalesce free blocks. */
	 
	i = 1;
	if (gdbm_setopt(dbp, GDBM_COALESCEBLKS, &i, sizeof(int)) == -1) {
		gdbm_error = (char *)gdbm_strerror(gdbm_errno);
		logf(copen, dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0);
		return (1);
	}

	/* If we're standalone, having GDBM wait for each write is a
	 * performance no-no; run non-synchronous */
	
	if (mudstate.standalone)
		dddb_setsync(0);

	/* Grab the file descriptor for locking */
	
	mudstate.dbm_fd = gdbm_fdesc(dbp);

	db_initted = 1;
	return (0);
}

int dddb_setfile(fil)
char *fil;
{
	char *xp;

	if (db_initted)
		return (1);

	/* KNOWN memory leak. can't help it. it's small */
	xp = XSTRDUP(fil, "dddb_setfile");
	if (xp == (char *)0)
		return (1);
	dbfile = xp;
	return (0);
}

int dddb_close()
{
	if (dbp != (GDBM_FILE) 0) {
		gdbm_close(dbp);   
		dbp = (GDBM_FILE) 0;
	}
	db_initted = 0;
	return (0);
}

/* Pass db_get a key, and it returns data. Type is used as part of the GDBM
 * key to guard against namespace conflicts in different MUSH subsystems.
 * It is the caller's responsibility to free the data returned by db_get */

DBData db_get(gamekey, type)
DBData gamekey;
unsigned int type;
{
	DBData gamedata;
	char *s;
#ifdef TEST_MALLOC
	char *newdat;
#endif
	
	if (!db_initted) {
		gamedata.dptr = NULL;
		gamedata.dsize = 0;
		return gamedata;
	}
	
	/* Construct a key (GDBM likes first 4 bytes to be unique) */
	
	s = key.dptr = (char *)RAW_MALLOC(sizeof(int) + gamekey.dsize, "db_get");
	memcpy((void *)s, gamekey.dptr, gamekey.dsize); 
	s += gamekey.dsize;
	memcpy((void *)s, (void *)&type, sizeof(unsigned int));
	key.dsize = sizeof(int) + gamekey.dsize;

	dat = gdbm_fetch(dbp, key);

#ifdef TEST_MALLOC
	/* We must XMALLOC() our own memory */
	if (dat.dptr != NULL) {
		newdat = (char *)XMALLOC(dat.dsize, "db_get.newdat");
		memcpy(newdat, dat.dptr, dat.dsize);
		free(dat.dptr);
		dat.dptr = newdat;
	}
#endif
	
	gamedata.dptr = dat.dptr;
	gamedata.dsize = dat.dsize;

	RAW_FREE(key.dptr, "db_get");
	return gamedata;
}

/* Pass db_put a key, data and the type of entry you are storing */

int db_put(gamekey, gamedata, type)
DBData gamekey;
DBData gamedata;
unsigned int type;
{
	char *s;
	
	if (!db_initted)
		return (1);

	/* Construct a key (GDBM likes first 4 bytes to be unique) */
	
	s = key.dptr = (char *)RAW_MALLOC(sizeof(int) + gamekey.dsize, "db_put");
	memcpy((void *)s, gamekey.dptr, gamekey.dsize); 
	s += gamekey.dsize;
	memcpy((void *)s, (void *)&type, sizeof(unsigned int));
	key.dsize = sizeof(int) + gamekey.dsize;
	
	/* make table entry */
	dat.dptr = gamedata.dptr;
	dat.dsize = gamedata.dsize;

	if (gdbm_store(dbp, key, dat, GDBM_REPLACE)) {
		logf("db_put: can't gdbm_store ", " ", (char *)-1, "\n", (char *)0);
		RAW_FREE(dat.dptr, "db_put.dat");
		RAW_FREE(key.dptr, "db_put");
		return (1);
	}

	RAW_FREE(key.dptr, "db_put");

	return (0);
}

/* Pass db_del a key and the type of entry you are deleting */

int db_del(gamekey, type)
DBData gamekey;
unsigned int type;
{
	char *s;
	
	if (!db_initted) {
		return (-1);
	}

	/* Construct a key (GDBM likes first 4 bytes to be unique) */
	
	s = key.dptr = (char *)RAW_MALLOC(sizeof(int) + gamekey.dsize, "db_del");
	memcpy((void *)s, gamekey.dptr, gamekey.dsize); 
	s += gamekey.dsize;
	memcpy((void *)s, (void *)&type, sizeof(unsigned int));
	key.dsize = sizeof(int) + gamekey.dsize;

	dat = gdbm_fetch(dbp, key); 

	/* not there? */
	if (dat.dptr == NULL) {
		RAW_FREE(key.dptr, "db_del.key");
		return (0);
	}

#ifdef TEST_MALLOC
	free(dat.dptr);
#else
	RAW_FREE(dat.dptr, "db_del.dat");
#endif

	/* drop key from db */
	if (gdbm_delete(dbp, key)) {
		logf("db_del: can't delete key\n", (char *)NULL);
		RAW_FREE(key.dptr, "db_del.key");
		return (1);
	}
	RAW_FREE(key.dptr, "db_del.key");
	return (0);
}

void db_lock()
{
	/* Attempt to lock the DBM file. Block until the lock is cleared,
	   then set it. */

	if (mudstate.dbm_fd == -1)
		return;

	fl.l_type = F_WRLCK;
	fl.l_whence = SEEK_SET;
	fl.l_start = 0;
	fl.l_len = 0;
	fl.l_pid = getpid();
	
	if (fcntl(mudstate.dbm_fd, F_SETLKW, &fl) == -1) {
		log_perror("DMP", "LOCK", NULL, "fcntl()");
		return;
	}
}

void db_unlock()
{
	if (mudstate.dbm_fd == -1)
		return;
		
	fl.l_type = F_UNLCK;
	
	if (fcntl(mudstate.dbm_fd, F_SETLK, &fl) == -1) {
		log_perror("DMP", "LOCK", NULL, "fcntl()");
		return;
	}
}