/*
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