/
umud/DOC/
umud/DOC/examples/
umud/DOC/internals/
umud/DOC/wizard/
umud/MISC/
umud/MISC/dbchk/
umud/RWHO/rwhod/
/*
	Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/

#ifndef	lint
static	char	RCSid[] = "$Header: /usr/users/mjr/hacks/umud/DB/RCS/hashdir.c,v 1.2 91/08/07 00:48:20 mjr Exp $";
#endif

/* configure all options BEFORE including system stuff. */
#include	"config.h"

#ifdef	DB_DIRHASH

#include	<stdio.h>


#include	<sys/types.h>
#include	<sys/file.h>
#include	<sys/param.h>

#ifdef	FCNTL_H
#include	<fcntl.h>
#endif

#ifdef	DIRENT
#include	<dirent.h>
#else
#include	<sys/dir.h>
#endif


#include	"mud.h"

/* default (runtime-resettable) directory hash size for permanent storage */
#ifndef	DEFAULT_HASH_SIZE
#define	DEFAULT_HASH_SIZE	11
#endif


/*
noisy complaints in the log if we can't find something. useful for
tracking "lost" objects
*/
#define HASHDIR_DEBUG

/*
default object storage routines. these store objects one per file in a
hashed directory structure. this is faster than it might seem at first,
and has the benefit of making it easy to online edit objects.
*/


/* initial hash directory pointer and hash size */
static	char	*hashpath = DEFAULT_HASHDIR;
static	int	hashsiz = DEFAULT_HASH_SIZE;
static	DIR	*dirp = (DIR *)0;
static	int	currdir = -1;

static	int	db_initted = 0;


/* initialize the database. this is pretty trivial in this version. :) */
int
dhdb_init()
{
	db_initted = 1;
	return(0);
}



int
dhdb_close()
{
	db_initted = 0;
	return(0);
}



/* is it initialized ? */
int
dhdb_initted()
{
	return(db_initted);
}



/* set hash table size */
int
dhdb_sethsiz(newsiz)
int	newsiz;
{
	return(hashsiz = newsiz);
}



/* configure hash path */
int
dhdb_sethpath(newpath)
char	*newpath;
{
	char	*xp;

	if(db_initted)
		return(1);

	xp = (char *)malloc((unsigned)(strlen(newpath) + 1));
	if(xp == (char *)0)
		return(1);
	(void)strcpy(xp,newpath);
	hashpath = xp;
	return(0);
}




/*
thaw an object from disk (or whatever) and return it, or NULL
in the event of an error. all you get is the name of the object
to thaw, and nothing more.
*/
Obj	*
dhdb_get(nam)
char	*nam;
{
	FILE	*inf;
	Obj	*ret;
	int	hv = 0;
	char	fn[MAXPATHLEN];
#ifdef NO_AT_IN_PATHS
	char	*p;
#endif

	if(!db_initted)
		return((Obj *)0);
	
	/* hash to directory slot on object # */
	hv = objid_hash(nam,hashsiz);

	(void)sprintf(fn,"%s/%d/%s",hashpath,hv,nam);
#ifdef NO_AT_IN_PATHS
	/* VMS hates @ in file names. Bash it into a _ */

	for(p = fn; *p != '\0' && *p; p++) {
		if(*p == '@') {
			*p = '_';
			break;
		}
	}
#endif

	if((inf = fopen(fn,"r")) == (FILE *)0) {
#ifdef	HASHDIR_DEBUG
		logf("db_get: cannot open ",fn," ",(char *)-1,"\n",(char *)0);
#endif
		return((Obj *)0);
	}

	/* if the file is badly formatted, ret == Obj * 0 */
	if((ret = oiffromFILE(inf,(char *)0)) == (Obj *)0)
		logf("db_get: cannot decode ",fn," ",(char *)-1,"\n",(char *)0);

	(void)fclose(inf);
	return(ret);
}





/*
freeze an object to disk (or whatever) and return 0, or -1.
*/
int
dhdb_put(obj,nam)
Obj	*obj;
char	*nam;
{
	FILE	*ofi;
	int	hv = 0;
	char	fn[MAXPATHLEN];
#ifdef NO_AT_IN_PATHS
	char	*p;
#endif

	if(!db_initted)
		return(1);
	
	hv = objid_hash(nam,hashsiz);

	(void)sprintf(fn,"%s/%d/%s",hashpath,hv,nam);
#ifdef NO_AT_IN_PATHS
	/* VMS hates @ in file names. Bash it into a _ */

	for(p = fn; *p != '\0' && *p; p++) {
		if(*p == '@') {
			*p = '_';
			break;
		}
	}
#endif

	if((ofi = fopen(fn,"w")) == (FILE *)0) {
#ifdef	HASHDIR_DEBUG
		logf("db_put: can't open ",fn," ",(char *)-1,"\n",(char *)0);
#endif
		return(-1);
	}

	if((hv = oiftoFILE(obj,ofi,nam)) != 0)
		logf("db_put: can't save ",fn," ",(char *)-1,"\n",(char *)0);

	(void)fclose(ofi);
	return(hv);
}




/*
probe for existence of the object in the database. this could use
access(2), but it's a stupid system call and I don't like it. plus,
no two systems seem to do it the same way (other than stupid).
*/
int
dhdb_check(nam)
char	*nam;
{
#ifdef NO_AT_IN_PATHS
	char	*p;
#endif
	int	fd = 0;
	char	fn[MAXPATHLEN];

	if(!db_initted)
		return(0);
	
	/* hash to directory slot on object # */
	fd = objid_hash(nam,hashsiz);

	(void)sprintf(fn,"%s/%d/%s",hashpath,fd,nam);
#ifdef NO_AT_IN_PATHS
	for(p = fn; *p != '\0' && *p; p++) {
		if(*p == '@') {
			*p = '_';
			break;
		}
	}
#endif
	if((fd = open(fn,O_RDONLY,0600)) < 0)
		return(0);

	(void)close(fd);
	return(1);
}




/*
clobber something out of the database
*/
int
dhdb_del(nam,flg)
char	*nam;
int	flg;
{
#ifdef NO_AT_IN_PATHS
	char	*p;
#endif
	char	fn[MAXPATHLEN];
	
	if(!db_initted)
		return(1);

	(void)sprintf(fn,"%s/%d/%s",hashpath,objid_hash(nam,hashsiz),nam);
#ifdef NO_AT_IN_PATHS
	/* VMS hates @ in file names. Bash it into a _ */

	for(p = fn; *p != '\0' && *p; p++) {
		if(*p == '@') {
			*p = '_';
			break;
		}
	}
#endif

	unlink(fn);
	return(0);
}




int
dhdb_travstart()
{
	char	fn[MAXPATHLEN];

	/* already open */
	if(!db_initted || currdir != -1 || dirp != (DIR *)0)
		return(1);

	currdir = 0;
	
	(void)sprintf(fn,"%s/%d",hashpath,currdir);
	if((dirp = opendir(fn)) == (DIR *)0)
		return(1);
	return(0);
}



int
dhdb_traverse(ob)
char	*ob;
{
#ifdef	DIRENT
	struct	dirent	*drp;
#else
	struct	direct	*drp;
#endif
	char	fn[MAXPATHLEN];

	if(!db_initted)
		return(0);

	while(1) {
#ifdef	DIRENT
		if((drp = readdir(dirp)) == (struct dirent *)0) {
#else
		if((drp = readdir(dirp)) == (struct direct *)0) {
#endif
			if(++currdir >= hashsiz)
				return(0);
			closedir(dirp);
			(void)sprintf(fn,"%s/%d",hashpath,currdir);
			if((dirp = opendir(fn)) == (DIR *)0)
				break;
			continue;
		}
		if(drp->d_name[0] == '.')
			continue;
		strncpy(ob,drp->d_name,MAXOID);
		return(1);
	}
	return(0);
}



int
dhdb_travend()
{
	if(!db_initted)
		return(0);

	if(dirp != (DIR *)0) {
		closedir(dirp);
		dirp = (DIR *)0;
		currdir = -1;
	}
	return(0);
}




dhdb_backup(out)
char	*out;
{
#ifdef	DIRENT
	struct	dirent	*drp;
#else
	struct	direct	*drp;
#endif
	int	red;
	char	buf[BUFSIZ];
	char	fn[MAXPATHLEN];
	int	ifd;
	int	ofd;

	currdir = 0;
	
	(void)sprintf(fn,"%s/%d",hashpath,currdir);
	if((dirp = opendir(fn)) == (DIR *)0)
		return(1);

	if((ofd = open(out,O_WRONLY|O_CREAT,0600)) < 0) {
		closedir(dirp);
		dirp = (DIR *)0;
		return(1);
	}


	while(1) {
#ifdef	DIRENT
		if((drp = readdir(dirp)) == (struct dirent *)0) {
#else
		if((drp = readdir(dirp)) == (struct direct *)0) {
#endif
			if(++currdir >= hashsiz)
				break;

			closedir(dirp);
			(void)sprintf(fn,"%s/%d",hashpath,currdir);
			if((dirp = opendir(fn)) == (DIR *)0)
				break;
			continue;
		}

		if(drp->d_name[0] == '.')
			continue;

		/* copy file out */
		(void)sprintf(fn,"%s/%d/%s",hashpath,currdir,drp->d_name);
		if((ifd = open(fn,O_RDONLY,0600)) < 0) {
			logf("db_backup: can't open ",fn," ",(char *)-1,"\n",(char *)0);
			continue;
		}

		while((red = read(ifd,buf,sizeof(buf))) > 0) {
			if(write(ofd,buf,red) != red) {
				logf("db_backup: can't write ",(char *)-1,"\n",(char *)0);
				close(ifd);
				break;
			}
		}
		close(ifd);
	}

	closedir(dirp);
	dirp = (DIR *)0;

	close(ofd);
	return(0);
}
#endif	DB_DIRHASH