/* bsddbm.c */ #include "config.h" /* * This file is part of TeenyMUD II. * Copyright(C) 1993, 1994, 1995 by Jason Downs. * All rights reserved. * * TeenyMUD II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * TeenyMUD II is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file 'COPYING'); if not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * */ #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #ifdef HAVE_MALLOC_H #include <malloc.h> #endif /* HAVE_MALLOC_H */ #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif /* HAVE_STDLIB_H */ #include <db.h> #include "conf.h" #include "teeny.h" #include "teenydb.h" #include "externs.h" /* TeenyMUD 4.4BSD database library interface. */ static DB *dbp = (DB *)NULL; static DBT key, cont; static int *obj_work = (int *)NULL; static int work_siz = 0; static int fast = 0; INLINE static char *bsd_pack_data _ANSI_ARGS_((char *, char *, int)); static char *bsd_pack_lock _ANSI_ARGS_((char *, struct boolexp *)); INLINE static char *bsd_pack_string _ANSI_ARGS_((char *, char *)); static void bsd_emergency_growbuf _ANSI_ARGS_((void)); INLINE static char *bsd_unpack_data _ANSI_ARGS_((char *, char *, int)); static char *bsd_unpack_lock _ANSI_ARGS_((struct boolexp **, char *)); INLINE static char *bsd_unpack_string _ANSI_ARGS_((char **, char *)); extern int errno; #define ALIGN(p) (((int)p) % sizeof(int) == 0 ? ((int)p) : \ ((int)p) + sizeof(int) - ((int)p) % sizeof(int)) int dbmfile_open(name, flags) char *name; int flags; { HASHINFO hinfo; hinfo.bsize = 8128; /* bucket size */ hinfo.cachesize = 10240L; /* small cache */ hinfo.ffactor = 36; hinfo.hash = NULL; hinfo.lorder = 0; hinfo.nelem = mudstat.total_objects; /* heh. */ if((dbp = dbopen(name, O_RDWR, 0600, DB_HASH, &hinfo)) == NULL) { logfile(LOG_ERROR, "dbmfile_open: couldn't open %s, %s.\n", name, strerror(errno)); return(-1); } if (flags & TEENY_DBMFAST) { fast = 1; } else fast = 0; return(0); } int dbmfile_init(name, flags) char *name; int flags; { HASHINFO hinfo; hinfo.bsize = 8128; /* bucket size */ hinfo.cachesize = 10240L; /* small cache */ hinfo.ffactor = 36; hinfo.hash = NULL; hinfo.lorder = 0; hinfo.nelem = mudstat.total_objects; /* heh. */ dbp = dbopen(name, O_RDWR|O_CREAT|O_TRUNC, 0600, DB_HASH, &hinfo); if(dbp == NULL) { logfile(LOG_ERROR, "dbmfile_init: couldn't open %s, %s\n", name, strerror(errno)); return(-1); } if (flags & TEENY_DBMFAST) { fast = 1; } else fast = 0; return(0); } void dbmfile_close() { (dbp->close)(dbp); } INLINE static char *bsd_pack_data(dest, source, size) char *dest, *source; int size; { bcopy((VOID *)source, (VOID *)dest, size); return((char *)(dest + size)); } static char *bsd_pack_lock(dest, src) char *dest; struct boolexp *src; { if(src == (struct boolexp *)NULL) { short type = BOOLEXP_END; /* i just *had* to use short... */ return(bsd_pack_data(dest, (char *)&type, sizeof(short))); } dest = bsd_pack_data(dest, (char *)&(src->type), sizeof(short)); switch(src->type) { case BOOLEXP_AND: case BOOLEXP_OR: dest = bsd_pack_lock((char *)ALIGN(dest), src->sub2); case BOOLEXP_NOT: dest = bsd_pack_lock((char *)ALIGN(dest), src->sub1); break; case BOOLEXP_CONST: dest = bsd_pack_data((char *)ALIGN(dest), (char *)&((src->dat).thing), sizeof(int)); break; case BOOLEXP_FLAG: dest = bsd_pack_data((char *)ALIGN(dest), (char *)((src->dat).flags), sizeof(int) * FLAGS_LEN); break; case BOOLEXP_ATTR: dest = bsd_pack_string((char *)ALIGN(dest), (src->dat).atr[0]); dest = bsd_pack_string((char *)ALIGN(dest), (src->dat).atr[1]); break; default: logfile(LOG_ERROR, "bsd_pack_lock: bad boolexp type (%d)\n", src->type); dest[-1] = BOOLEXP_END; } return(dest); } INLINE static char *bsd_pack_string(dest, src) register char *dest, *src; { register int len; if(src == (char *)NULL){ dest[0] = '\0'; return((char *)(dest + 1)); } #ifdef notyet if(mudconf.enable_compress) { register char *csrc; csrc = compress(src); len = strlen(csrc)+1; bcopy((VOID *)csrc, (VOID *)dest, len); ty_free(csrc); } else { len = strlen(src)+1; bcopy((VOID *)src, (VOID *)dest, len); } #else len = strlen(src)+1; bcopy((VOID *)src, (VOID *)dest, len); #endif return((char *)(dest + len)); } static void bsd_emergency_growbuf() { obj_work = (int *) ty_realloc(obj_work, work_siz + MEDBUFFSIZ, "bsd_emergency_growbuf"); work_siz += MEDBUFFSIZ; } int disk_freeze(data) struct obj_data *data; { char *ptr; int *iptr; struct attr *attrs; int obj; register int idx; obj = data->objnum; if (!(DSC_FLAG2(main_index[obj]) & IN_MEMORY)) { logfile(LOG_ERROR, "disk_freeze: attempt to freeze non-resident object #%d\n", obj); return(-1); } if ((work_siz == 0) && DSC_SIZE(main_index[obj]) < 10240) { /* initialize our buffer */ obj_work = (int *) ty_malloc(10240L, "disk_freeze.obj_work"); work_siz = 10240L; } if (DSC_SIZE(main_index[obj]) > work_siz) { /* grow it */ ty_free((VOID *) obj_work); obj_work = (int *) ty_malloc(DSC_SIZE(main_index[obj]) + MEDBUFFSIZ, "disk_freeze.obj_work"); work_siz = DSC_SIZE(main_index[obj]) + MEDBUFFSIZ; } bzero((VOID *)obj_work, work_siz); /* malloc'd memory should always be aligned, damnit. */ iptr = obj_work; *iptr++ = data->quota; *iptr++ = data->loc; *iptr++ = data->contents; *iptr++ = data->exits; *iptr++ = data->rooms; *iptr++ = data->timestamp; *iptr++ = data->created; *iptr++ = data->usecnt; *iptr++ = data->charges; *iptr++ = data->semaphores; *iptr++ = data->cost; *iptr++ = data->queue; /* attributes */ *iptr++ = data->attr_total; ptr = (char *)iptr; for(idx = 0; idx < ATTR_WIDTH; idx++) { for(attrs = data->attributes[idx]; attrs != (struct attr *)NULL; attrs = attrs->next) { ptr = bsd_pack_data((char *)ALIGN(ptr), (char *)&attrs->type, sizeof(short)); ptr = bsd_pack_string((char *)ALIGN(ptr), attrs->name); if ((ptr - (char *)obj_work) > (work_siz - MEDBUFFSIZ)) bsd_emergency_growbuf(); switch(attrs->type) { case ATTR_STRING: ptr = bsd_pack_string((char *)ALIGN(ptr), (attrs->dat).str); break; case ATTR_LOCK: ptr = bsd_pack_lock((char *)ALIGN(ptr), (attrs->dat).lock); break; } ptr = bsd_pack_data((char *)ALIGN(ptr), (char *)&attrs->flags, sizeof(int)); if ((ptr - (char *)obj_work) > (work_siz - MEDBUFFSIZ)) bsd_emergency_growbuf(); } } /* strings and such. */ ptr = bsd_pack_string((char *)ALIGN(ptr), data->name); /* set it up. */ key.data = (VOID *) &obj; key.size = sizeof(int); cont.data = (VOID *) obj_work; cont.size = ptr - (char *)obj_work; /* store it. */ if((dbp->put)(dbp, &key, &cont, 0) != 0){ logfile(LOG_ERROR, "disk_freeze: failed to store object #%d, %s.\n", obj, strerror(errno)); mudstat.cache_errors++; return(-1); } /* sync it. */ if(!fast) { if((dbp->sync)(dbp, 0) == -1) { logfile(LOG_ERROR, "disk_freeze: failed to sync the database.\n"); } } /* all done! */ DSC_FLAG2(main_index[obj]) &= ~IN_MEMORY; free_obj(data); return(0); } INLINE static char *bsd_unpack_data(dest, source, size) char *dest, *source; int size; { bcopy((VOID *)source, (VOID *)dest, size); return((char *)(source + size)); } static char *bsd_unpack_lock(dest, source) struct boolexp **dest; char *source; { short type; source = bsd_unpack_data((char *)&type, source, sizeof(short)); switch(type) { case BOOLEXP_END: *dest = (struct boolexp *)NULL; return(source); case BOOLEXP_AND: case BOOLEXP_OR: *dest = boolexp_alloc(); (*dest)->type = type; source = bsd_unpack_lock(&(*dest)->sub2, (char *)ALIGN(source)); return(bsd_unpack_lock(&(*dest)->sub1, (char *)ALIGN(source))); case BOOLEXP_NOT: *dest = boolexp_alloc(); (*dest)->type = type; return(bsd_unpack_lock(&(*dest)->sub1, (char *)ALIGN(source))); case BOOLEXP_CONST: *dest = boolexp_alloc(); (*dest)->type = type; return(bsd_unpack_data((char *)&((*dest)->dat).thing, (char *)ALIGN(source), sizeof(int))); case BOOLEXP_FLAG: *dest = boolexp_alloc(); (*dest)->type = type; return(bsd_unpack_data((char *)((*dest)->dat).flags, (char *)ALIGN(source), sizeof(int) * FLAGS_LEN)); case BOOLEXP_ATTR: *dest = boolexp_alloc(); (*dest)->type = type; source = bsd_unpack_string(&(((*dest)->dat).atr[0]), (char *)ALIGN(source)); return(bsd_unpack_string(&(((*dest)->dat).atr[1]), (char *)ALIGN(source))); default: logfile(LOG_ERROR, "bsd_unpack_lock: bad boolexp type (%c)\n", *source); *dest = (struct boolexp *)NULL; return(source); } } INLINE static char *bsd_unpack_string(dest, source) char **dest, *source; { register char *ptr = source; if(ptr[0] == '\0') { *dest = (char *)NULL; return((char *)(source + 1)); } while(ptr[0] != '\0') ptr++; ptr++; #ifdef notyet *dest = uncompress(source); #else *dest = ty_strdup(source, "bsddbm_unpack_string.ret"); #endif return(ptr); } struct obj_data *disk_thaw(obj) int obj; { struct obj_data *ret; int *iptr, *data; char *ptr; register int attr_total, hashval; struct attr *curr; if (DSC_FLAG2(main_index[obj]) & IN_MEMORY) { logfile(LOG_ERROR, "disk_thaw: attempt to re-thaw thawed object #%d\n", obj); return (DSC_DATA(main_index[obj])); } /* set it up. */ key.data = (VOID *) &obj; key.size = sizeof(int); /* fetch it. */ if((dbp->get)(dbp, &key, &cont, 0) != 0) { logfile(LOG_ERROR, "disk_thaw: couldn't fetch object #%d, %s.\n", obj, strerror(errno)); return((struct obj_data *)NULL); } ret = (struct obj_data *) ty_malloc(sizeof(struct obj_data), "disk_thaw.ret"); ret->objnum = obj; /* this is lame. */ if(cont.size <= work_siz) { data = obj_work; } else { data = (int *)ty_malloc(cont.size, "disk_thaw.data"); } /* bsd does not align it's return data. */ bcopy((VOID *)cont.data, (VOID *)data, cont.size); iptr = data; ret->quota = *iptr++; ret->loc = *iptr++; ret->contents = *iptr++; ret->exits = *iptr++; ret->rooms = *iptr++; ret->timestamp = *iptr++; ret->created = *iptr++; ret->usecnt = *iptr++; ret->charges = *iptr++; ret->semaphores = *iptr++; ret->cost = *iptr++; ret->queue = *iptr++; ptr = (char *)iptr; /* attributes. */ bzero((VOID *)ret->attributes, sizeof(struct attr *) * ATTR_WIDTH); ptr = bsd_unpack_data((char *)&ret->attr_total, ptr, sizeof(int)); attr_total = ret->attr_total; while(attr_total) { curr = (struct attr *)ty_malloc(sizeof(struct attr), "disk_thaw.curr"); ptr = bsd_unpack_data((char *)&curr->type, (char *)ALIGN(ptr), sizeof(short)); ptr = bsd_unpack_string(&curr->name, (char *)ALIGN(ptr)); switch(curr->type) { case ATTR_STRING: ptr = bsd_unpack_string(&(curr->dat).str, (char *)ALIGN(ptr)); break; case ATTR_LOCK: ptr = bsd_unpack_lock(&(curr->dat).lock, (char *)ALIGN(ptr)); break; } ptr = bsd_unpack_data((char *)&curr->flags, (char *)ALIGN(ptr), sizeof(int)); hashval = attr_hash(curr->name); curr->next = ret->attributes[hashval]; if(ret->attributes[hashval] == (struct attr *)NULL) curr->prev = curr; else { curr->prev = (ret->attributes[hashval])->prev; (ret->attributes[hashval])->prev = curr; } ret->attributes[hashval] = curr; attr_total--; } /* strings and such. */ ptr = bsd_unpack_string(&ret->name, (char *)ALIGN(ptr)); DSC_DATA(main_index[obj]) = ret; DSC_FLAG2(main_index[obj]) |= IN_MEMORY; DSC_FLAG2(main_index[obj]) &= ~DIRTY; if(data != obj_work) ty_free((VOID *)data); return(ret); } void disk_delete(data) struct obj_data *data; { key.data = (VOID *) &data->objnum; key.size = sizeof(int); if((dbp->del)(dbp, &key, 0) != 0) { logfile(LOG_ERROR, "disk_delete: couldn't delete object #%d, %s.\n", data->objnum, strerror(errno)); } }