/* Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ /* configure all options BEFORE including system stuff. */ #include "config.h" #ifdef DB_DBMFILE #ifdef OLDDBM #ifdef WIN32 #include "dbm.h" #else #include <dbm.h> #endif #else #ifdef WIN32 #include "ndbm.h" #else #include <ndbm.h> #endif #endif #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 void dddb_mark (off_t lbn, int siz, int taken); static void growbit (int maxblok); 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; int dddb_init (void) { static char *copen = "db_init cannot open "; char fnam[MAXPATHLEN]; struct stat sbuf; #ifdef COMPRESS_OIF comp_init (); comp_on (1); #endif /* now open chunk file */ sprintf (fnam, "%s.db", dbfile); /* first try to open existing file then try opening new file */ if ((dbf = fopen (fnam, "rb+")) == (FILE *) 0) { if ((dbf = fopen (fnam, "wb+")) == (FILE *) 0) { log_printf (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) { log_printf (copen, dbfile, " ", (char *) -1, "\n", (char *) 0); return (1); } sprintf (fnam, "%s.dir", dbfile); fxp = open (fnam, O_CREAT | O_EXCL | O_WRONLY, S_IREAD | S_IWRITE); if (fxp < 0) { log_printf (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, S_IREAD | S_IWRITE); if (fxp < 0) { log_printf (copen, fnam, " ", (char *) -1, "\n", (char *) 0); return (1); } (void) close (fxp); /* one MORE try */ if ((dbp = dbminit (dbfile)) < 0) { log_printf (copen, dbfile, " ", (char *) -1, "\n", (char *) 0); return (1); } } #else if ((dbp = dbm_open (dbfile, O_RDWR | O_CREAT, S_IREAD | S_IWRITE)) == (DBM *) 0) { log_printf (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)) { log_printf ("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) { log_printf ("db_init index inconsistent\n", (char *) 0); return (1); } bcopy (dat.dptr, (char *) &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); } int dddb_initted (void) { return (db_initted); } int dddb_setbsiz (int nbsiz) { return (bsiz = nbsiz); } int dddb_setfile (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 (void) { 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 (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, (unsigned) ((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 void dddb_mark (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 (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 (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, (char *) &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) log_printf ("db_get: cannot decode ", nam, "\n", (char *) 0); return (ret); } int dddb_put (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, (char *) &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)) { log_printf ("db_put: can't store ", nam, " ", (char *) -1, "\n", (char *) 0); return (1); } #else if (dbm_store (dbp, key, dat, DBM_REPLACE)) { log_printf ("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)) { log_printf ("db_put: can't seek ", nam, " ", (char *) -1, "\n", (char *) 0); return (1); } if (oiftoFILE (obj, dbf, nam) != 0 || fflush (dbf) != 0) { log_printf ("db_put: can't save ", nam, " ", (char *) -1, "\n", (char *) 0); return (1); } return (0); } int dddb_check (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 (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, (char *) &hbuf, sizeof (hbuf)); /* drop key from db */ #ifdef OLDDBM if (delete (key)) { #else if (dbm_delete (dbp, key)) { #endif log_printf ("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)) log_printf ("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 (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 (char *out) { FILE *ou; char vuf[BUFSIZ]; int tor; if (!db_initted) return (1); if ((ou = fopen (out, "wb")) == (FILE *) 0) { log_printf ("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) { log_printf ("db_init index inconsistent\n", (char *) 0); continue; } bcopy (dat.dptr, (char *) &hbuf, sizeof (hbuf)); if (fseek (dbf, (long) hbuf.off, 0)) log_printf ("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) { log_printf ("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