/* Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ #ifndef lint static char RCSid[] = "$Header: /usr/users/mjr/hacks/umud/DB/RCS/dbmchunk.c,v 1.7 91/08/18 21:49:38 mjr Exp $"; #endif /* configure all options BEFORE including system stuff. */ #include "config.h" #ifdef DB_DBMFILE #ifdef VMS #include <stdio.h> #include <types.h> #include <file.h> #include <unixio.h> #include "vms_dbm.h" #else #include <stdio.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/file.h> #ifdef FCNTL_H #include <fcntl.h> #endif #ifdef OLDDBM #include <dbm.h> #include <sys/errno.h> extern int errno; #else #include <ndbm.h> #endif #endif VMS #include "mud.h" #include "sbuf.h" /* #define DBMCHUNK_DEBUG */ /* default block size to use for bitmapped chunks */ #define DDDB_BLOCK 256 /* bitmap growth increment in BLOCKS not bytes (512 is 64 BYTES) */ #define DDDB_BITBLOCK 512 #define LOGICAL_BLOCK(off) (off/bsiz) #define BLOCK_OFFSET(block) (block*bsiz) #define BLOCKS_NEEDED(siz) (siz % bsiz ? (siz / bsiz) + 1 : (siz / bsiz)) /* dbm-based object storage routines. Somewhat trickier than the default directory hash. a free space list is maintained as a bitmap of free blocks, and an object-pointer list is maintained in a dbm database. */ struct hrec { off_t off; int siz; }; static int dddb_mark(); static char *dbfile = DEFAULT_DBMCHUNKFILE; static int bsiz = DDDB_BLOCK; static int db_initted = 0; static int last_free = 0; /* last known or suspected free block */ #ifdef OLDDBM static int dbp = 0; #else static DBM *dbp = (DBM *)0; #endif static FILE *dbf = (FILE *)0; static struct hrec hbuf; static int startrav = 0; static char *bitm = (char *)0; static int bitblox = 0; static datum dat; static datum key; static void growbit(); int dddb_init() { static char *copen = "db_init cannot open "; char fnam[MAXPATHLEN]; struct stat sbuf; struct hrec *hp; #ifdef COMPRESS_OIF comp_init(); comp_on(1); #endif /* now open chunk file */ sprintf(fnam,"%s.db",dbfile); if((dbf = fopen(fnam,FOPEN_BINARY_RW)) == (FILE *)0) { logf(copen,fnam," ",(char *)-1,"\n",(char *)0); return(1); } /* open hash table */ #ifdef OLDDBM if((dbp = dbminit(dbfile)) < 0) { int fxp; /* dbm (old) is stupid about nonexistent files */ if(errno != ENOENT) { logf(copen,dbfile," ",(char *)-1,"\n",(char *)0); return(1); } sprintf(fnam,"%s.dir",dbfile); fxp = open(fnam,O_CREAT|O_EXCL|O_WRONLY,0600); if(fxp < 0) { logf(copen,fnam," ",(char *)-1,"\n",(char *)0); return(1); } (void)close(fxp); sprintf(fnam,"%s.pag",dbfile); fxp = open(fnam,O_CREAT|O_EXCL|O_WRONLY,0600); if(fxp < 0) { logf(copen,fnam," ",(char *)-1,"\n",(char *)0); return(1); } (void)close(fxp); /* one MORE try */ if((dbp = dbminit(dbfile)) < 0) { logf(copen,dbfile," ",(char *)-1,"\n",(char *)0); return(1); } } #else if((dbp = dbm_open(dbfile,O_RDWR|O_CREAT,0600)) == (DBM *)0) { logf(copen,dbfile," ",(char *)-1,"\n",(char *)0); return(1); } #endif /* determine size of chunk file for allocation bitmap */ sprintf(fnam,"%s.db",dbfile); if(stat(fnam,&sbuf)) { logf("db_init cannot stat ",fnam," ",(char *)-1,"\n",(char *)0); return(1); } /* allocate bitmap */ growbit(LOGICAL_BLOCK(sbuf.st_size) + DDDB_BITBLOCK); #ifdef OLDDBM key = firstkey(); #else key = dbm_firstkey(dbp); #endif while(key.dptr != (char *)0) { #ifdef OLDDBM dat = fetch(key); #else dat = dbm_fetch(dbp,key); #endif if(dat.dptr == (char *)0) { logf("db_init index inconsistent\n",(char *)0); return(1); } bcopy(dat.dptr,&hbuf,sizeof(hbuf)); /* alignment */ /* mark it as busy in the bitmap */ dddb_mark(LOGICAL_BLOCK(hbuf.off),hbuf.siz,1); #ifdef OLDDBM key = nextkey(key); #else key = dbm_nextkey(dbp); #endif } db_initted = 1; return(0); } dddb_initted() { return(db_initted); } dddb_setbsiz(nbsiz) int nbsiz; { return(bsiz = nbsiz); } dddb_setfile(fil) char *fil; { char *xp; if(db_initted) return(1); /* KNOWN memory leak. can't help it. it's small */ xp = (char *)malloc((unsigned)strlen(fil) + 1); if(xp == (char *)0) return(1); (void)strcpy(xp,fil); dbfile = xp; return(0); } int dddb_close() { if(dbf != (FILE *)0) { fclose(dbf); dbf = (FILE *)0; } #ifndef OLDDBM if(dbp != (DBM *)0) { dbm_close(dbp); dbp = (DBM *)0; } #endif if(bitm != (char *)0) { free((mall_t)bitm); bitm = (char *)0; bitblox = 0; } db_initted = 0; return(0); } /* grow the bitmap to given size */ static void growbit(maxblok) int maxblok; { int nsiz; char *nbit; /* round up to eight and then some */ nsiz = (maxblok + 8) + (8 - (maxblok % 8)); if(nsiz <= bitblox) return; /* this done because some old realloc()s are busted */ nbit = (char *)malloc((unsigned)(nsiz / 8)); if(bitm != (char *)0) { bcopy(bitm,nbit,(bitblox / 8) - 1); free((mall_t)bitm); } bitm = nbit; if(bitm == (char *)0) fatal("db_init cannot grow bitmap ",(char *)-1,"\n",(char *)0); bzero(bitm + (bitblox / 8),((nsiz / 8) - (bitblox / 8)) - 1); bitblox = nsiz - 8; } static int dddb_mark(lbn,siz,taken) off_t lbn; int siz; int taken; { int bcnt; bcnt = BLOCKS_NEEDED(siz); /* remember a free block was here */ if(!taken) last_free = lbn; while(bcnt--) { if(lbn >= bitblox - 32) growbit(lbn + DDDB_BITBLOCK); if(taken) bitm[lbn >> 3] |= (1 << (lbn & 7)); else bitm[lbn >> 3] &= ~(1 << (lbn & 7)); lbn++; } } static int dddb_alloc(siz) int siz; { int bcnt; /* # of blocks to operate on */ int lbn; /* logical block offset */ int tbcnt; int slbn; int overthetop = 0; lbn = last_free; bcnt = siz % bsiz ? (siz / bsiz) + 1 : (siz / bsiz); while(1) { if(lbn >= bitblox - 32) { /* only check here. can't break around the top */ if(!overthetop) { lbn = 0; overthetop++; } else { growbit(lbn + DDDB_BITBLOCK); } } slbn = lbn; tbcnt = bcnt; while(1) { if((bitm[lbn >> 3] & (1 << (lbn & 7))) != 0) break; /* enough free blocks - mark and done */ if(--tbcnt == 0) { for(tbcnt = slbn; bcnt > 0; tbcnt++, bcnt--) bitm[tbcnt >> 3] |= (1 << (tbcnt & 7)); last_free = lbn; return(slbn); } lbn++; if(lbn >= bitblox - 32) growbit(lbn + DDDB_BITBLOCK); } lbn++; } } Obj * dddb_get(nam) char *nam; { Obj *ret; if(!db_initted) return((Obj *)0); key.dptr = nam; key.dsize = strlen(nam) + 1; #ifdef OLDDBM dat = fetch(key); #else dat = dbm_fetch(dbp,key); #endif if(dat.dptr == (char *)0) return((Obj *)0); bcopy(dat.dptr,&hbuf,sizeof(hbuf)); /* seek to location */ if(fseek(dbf,(long)hbuf.off,0)) return((Obj *)0); /* if the file is badly formatted, ret == Obj * 0 */ if((ret = oiffromFILE(dbf,(char *)0)) == (Obj *)0) logf("db_get: cannot decode ",nam,"\n",(char *)0); return(ret); } int dddb_put(obj,nam) Obj *obj; char *nam; { int nsiz; if(!db_initted) return(1); nsiz = oif_objsiz(obj,nam); key.dptr = nam; key.dsize = strlen(nam) + 1; #ifdef OLDDBM dat = fetch(key); #else dat = dbm_fetch(dbp,key); #endif if(dat.dptr != (char *)0) { bcopy(dat.dptr,&hbuf,sizeof(hbuf)); /* align */ if(BLOCKS_NEEDED(nsiz) > BLOCKS_NEEDED(hbuf.siz)) { #ifdef DBMCHUNK_DEBUG printf("put: %s old %d < %d - free %d\n",nam,hbuf.siz,nsiz,hbuf.off); #endif /* mark free in bitmap */ dddb_mark(LOGICAL_BLOCK(hbuf.off),hbuf.siz,0); hbuf.off = BLOCK_OFFSET(dddb_alloc(nsiz)); hbuf.siz = nsiz; #ifdef DBMCHUNK_DEBUG printf("put: %s moved to offset %d, size %d\n",nam,hbuf.off,hbuf.siz); #endif } else { hbuf.siz = nsiz; #ifdef DBMCHUNK_DEBUG printf("put: %s replaced within offset %d, size %d\n",nam,hbuf.off,hbuf.siz); #endif } } else { hbuf.off = BLOCK_OFFSET(dddb_alloc(nsiz)); hbuf.siz = nsiz; #ifdef DBMCHUNK_DEBUG printf("put: %s (new) at offset %d, size %d\n",nam,hbuf.off,hbuf.siz); #endif } /* make table entry */ dat.dptr = (char *)&hbuf; dat.dsize = sizeof(hbuf); #ifdef OLDDBM if(store(key,dat)) { logf("db_put: can't store ",nam," ",(char *)-1,"\n",(char *)0); return(1); } #else if(dbm_store(dbp,key,dat,DBM_REPLACE)) { logf("db_put: can't dbm_store ",nam," ",(char *)-1,"\n",(char *)0); return(1); } #endif #ifdef DBMCHUNK_DEBUG printf("%s offset %d size %d\n",nam,hbuf.off,hbuf.siz); #endif if(fseek(dbf,(long)hbuf.off,0)) { logf("db_put: can't seek ",nam," ",(char *)-1,"\n",(char *)0); return(1); } if(oiftoFILE(obj,dbf,nam) != 0 || fflush(dbf) != 0) { logf("db_put: can't save ",nam," ",(char *)-1,"\n",(char *)0); return(1); } return(0); } int dddb_check(nam) char *nam; { if(!db_initted) return(0); key.dptr = nam; key.dsize = strlen(nam) + 1; #ifdef OLDDBM dat = fetch(key); #else dat = dbm_fetch(dbp,key); #endif if(dat.dptr == (char *)0) return(0); return(1); } int dddb_del(nam,flg) char *nam; int flg; { if(!db_initted) return(-1); key.dptr = nam; key.dsize = strlen(nam) + 1; #ifdef OLDDBM dat = fetch(key); #else dat = dbm_fetch(dbp,key); #endif /* not there? */ if(dat.dptr == (char *)0) return(0); bcopy(dat.dptr,&hbuf,sizeof(hbuf)); /* drop key from db */ #ifdef OLDDBM if(delete(key)) { #else if(dbm_delete(dbp,key)) { #endif logf("db_del: can't delete key ",nam,"\n",(char *)0); return(1); } /* mark free space in bitmap */ dddb_mark(LOGICAL_BLOCK(hbuf.off),hbuf.siz,0); #ifdef DBMCHUNK_DEBUG printf("del: %s free offset %d, size %d\n",nam,hbuf.off,hbuf.siz); #endif /* mark object dead in file */ if(fseek(dbf,(long)hbuf.off,0)) logf("db_del: can't seek ",nam," ",(char *)-1,"\n",(char *)0); else { fprintf(dbf,"delobj"); fflush(dbf); } return(0); } int dddb_travstart() { startrav = 0; return(0); } int dddb_traverse(obuf) char *obuf; { if(!db_initted) return(0); if(!startrav) { #ifdef OLDDBM key = firstkey(); #else key = dbm_firstkey(dbp); #endif startrav = 1; } else #ifdef OLDDBM key = nextkey(key); #else key = dbm_nextkey(dbp); #endif if(key.dptr == (char *)0) return(0); strncpy(obuf,key.dptr,MAXOID); return(1); } int dddb_travend() { startrav = 0; return(0); } int dddb_backup(out) char *out; { FILE *ou; char vuf[BUFSIZ]; int tor; char *xx; if(!db_initted) return(1); if((ou = fopen(out,"w")) == (FILE *)0) { logf("db_backup: ",out," ",(char *)-1,"\n",(char *)0); return(1); } #ifdef OLDDBM key = firstkey(); #else key = dbm_firstkey(dbp); #endif while(key.dptr != (char *)0) { #ifdef OLDDBM dat = fetch(key); #else dat = dbm_fetch(dbp,key); #endif if(dat.dptr == (char *)0) { logf("db_init index inconsistent\n",(char *)0); continue; } bcopy(dat.dptr,&hbuf,sizeof(hbuf)); if(fseek(dbf,(long)hbuf.off,0)) logf("db_backup: can't seek ",key.dptr," ",(char *)-1,"\n",(char *)0); else { /* copy out the object, sans interpretation */ while(hbuf.siz > 0) { if((tor = hbuf.siz) > sizeof(vuf)) tor = sizeof(vuf); if(fread(vuf,sizeof(char),tor,dbf) <= 0) { logf("db_backup: can't read ",key.dptr," ",(char *)-1,"\n",(char *)0); break; } /* what are we gonna do if it fails, anyhow? */ fwrite(vuf,sizeof(char),tor,ou); hbuf.siz -= tor; } } #ifdef OLDDBM key = nextkey(key); #else key = dbm_nextkey(dbp); #endif } fclose(ou); return(0); } #endif DB_DBMFILE