/* disk.c */ #include "copyright.h" #include "config.h" #include <stdio.h> #ifdef STRING_H #include <string.h> #else #include <strings.h> #endif /* STRING_H */ #include <fcntl.h> #include <sys/types.h> #include <sys/file.h> #ifndef NO_UIO_H #include <sys/uio.h> #endif /* NO_UIO_H */ #include "teeny.h" #include "db.h" /* * Handles basic disk I/O for TeenyMUD. They mess with the descriptors * slightly, updating IN_MEMORY status and the where field of the descriptor. * */ char *snarf_str_field(); int *snarf_lock(); char *stuff_lock(); char *stuff_str_field(); int chunkfd; long lseek(); /* Berkeley thinks this is type off_t. Fuck * them. */ /* A work buffer. An on-disk object had better NEVER be bigger than this. */ int obj_work[MAX_DISK_SIZE / sizeof(int)]; /* * Write the object specified by the descriptor out to disk. Will not bother * to freeze an object that isn't dirty. * */ disk_freeze(d) struct dsc *d; { int *p; char *q; struct obj_data *dat; struct dsc *tmp; int total_size; long offset; long ret; if (!ResidentP(d)) { warning("disk_freeze", "attempt to freeze non-resident object"); return; } dat = DSC_DATA(d); /* Is the data for this thing dirty? If not, patch up its */ /* descriptor to point at the disk, and free the memory */ if (!DirtyP(d)) { offset = dat->offset; DSC_CHUNK(d) = offset; DSC_FLAGS(d) &= ~IN_MEMORY; free_obj(dat); return; } /* Does this thing already own a chunk of disk? */ if (dat->offset != (long) -1) { /* Make a descriptor for this chunk & give it back */ tmp = get_descriptor(); DSC_CHUNK(tmp) = dat->offset; DSC_SIZE(tmp) = dat->chunk_size; free_chunk(tmp); } /* Step one. Write the thing into our workspace. */ p = obj_work; *p++ = dat->pennies; *p++ = dat->loc; *p++ = dat->contents; *p++ = dat->exits; #ifdef TIMESTAMPS *p++ = dat->timestamp; #endif /* Stuff variable length integer arrays. */ /* NOTE: Order is important. These arrays *will* be correctly */ /* aligned, since they fall immediately after a mess of other */ /* integers. Effectively, we start with a huge array of ints. */ q = stuff_lock(p, dat->lock); /* Stuff variable length strings. Now alignment goes to hell */ /* Strings are zero terminated, so we don't care!!! */ q = stuff_str_field(q, dat->suc); q = stuff_str_field(q, dat->osuc); q = stuff_str_field(q, dat->fail); q = stuff_str_field(q, dat->ofail); #ifdef DROP_FIELDS q = stuff_str_field(q, dat->drop); q = stuff_str_field(q, dat->odrop); #endif q = stuff_str_field(q, dat->desc); q = stuff_str_field(q, dat->gender); /* Step two. How big is this bugger? Write it out to disk */ total_size = q - (char *) obj_work; if (total_size != DSC_SIZE(d)) { warning("disk_freeze", "computed disk size != stated"); } offset = get_chunk(total_size); #ifdef DISKDEBUG printf("Freeze seeking to offset %ld\n", offset); #endif ret = lseek(chunkfd, (off_t) offset, 0); ret = (long) write(chunkfd, (char *) obj_work, total_size); if (ret != total_size) { warning("disk_freeze", "failed write"); } /* Update descriptor */ DSC_CHUNK(d) = offset; DSC_FLAGS(d) &= ~IN_MEMORY; /* Free up the memory used. */ free_obj(dat); } free_obj(obj) struct obj_data *obj; { ty_free((char *) (obj->lock)); ty_free(obj->suc); ty_free(obj->osuc); ty_free(obj->fail); ty_free(obj->ofail); #ifdef DROP_FIELDS ty_free(obj->drop); ty_free(obj->odrop); #endif ty_free(obj->desc); ty_free(obj->gender); ty_free((char *) obj); } /* * Copies one of our internal arrays around. They start with a count of * number of ints, and are followed by that many ints. Yow. * */ char * stuff_lock(dst, src) int *dst, *src; { int count; if (src == NULL) { *dst++ = -1; /* Indicate empty lock */ return ((char *) dst); } count = *dst++ = *src++; /* The very first one is how many follow */ while (count > 0) { *dst++ = *src++; count--; } return ((char *) dst); } /* * Really just copies a string around, and returns a pointer to the first * byte after the string. * */ char * stuff_str_field(dst, src) char *dst, *src; { int len; if (src == NULL) { /* Shove in a zero length string */ *dst++ = '\0'; return (dst); } len = strlen(src); strcpy(dst, src); return (dst + len + 1); /* plus one for the \0 */ } /* * Read the object specified by the desriptor in from disk. */ struct obj_data * disk_thaw(d) struct dsc *d; { struct obj_data *new_obj; long ret; int len; long offset; char *q; int *p; if (ResidentP(d)) { warning("disk_thaw", "attempt to re-thaw thawed object"); return (DSC_DATA(d)); } offset = DSC_CHUNK(d); #ifdef DISKDEBUG printf("Thaw seeking to offset %ld\n", offset); #endif ret = lseek(chunkfd, (off_t) offset, 0); ret = (long) read(chunkfd, (char *) obj_work, DSC_SIZE(d)); if (ret != DSC_SIZE(d)) { warning("disk_thaw", "couldn't thaw chunk"); return (NULL); } /* OK. It's in memory. Snarf the data out */ len = DSC_SIZE(d); new_obj = (struct obj_data *) ty_malloc(sizeof(struct obj_data) ,"disk_thaw"); p = obj_work; /* Fix up internal object data fields. */ new_obj->offset = offset; new_obj->chunk_size = DSC_SIZE(d); new_obj->descriptor = d; new_obj->pennies = *p++; new_obj->loc = *p++; new_obj->contents = *p++; new_obj->exits = *p++; #ifdef TIMESTAMPS new_obj->timestamp = *p++; #endif /* Variable length field integer field. */ new_obj->lock = snarf_lock(&p); q = (char *) p; len -= (q - (char *) obj_work); /* Subtract what we've chopped off */ /* Variable length string fields. */ new_obj->suc = snarf_str_field(&q, &len); new_obj->osuc = snarf_str_field(&q, &len); new_obj->fail = snarf_str_field(&q, &len); new_obj->ofail = snarf_str_field(&q, &len); #ifdef DROP_FIELDS new_obj->drop = snarf_str_field(&q, &len); new_obj->odrop = snarf_str_field(&q, &len); #endif new_obj->desc = snarf_str_field(&q, &len); new_obj->gender = snarf_str_field(&q, &len); /* Update the descriptor */ DSC_DATA(d) = new_obj; DSC_FLAGS(d) |= IN_MEMORY; DSC_FLAGS(d) &= ~DIRTY; return (new_obj); } /* * Copy an array of our integers into new fresh memory. * * src had damn well better be aligned enough. * */ int * snarf_lock(src) int **src; { int len; int *p; len = *(*src); /* First thing is how many there are to * follow */ if (len == -1) { /* No lock, empty */ (*src)++; return (NULL); } len++; /* Add one for the length field, of course */ p = (int *) ty_malloc((len * sizeof(int)), "snarf_lock"); /* Ignore returned value, we care not. */ (void) stuff_lock(p, *src); *src += len; return (p); } /* * Grabs a variable length string field out of a buffer. String should be * zero terminated. */ char * snarf_str_field(src, remaining) char **src; int *remaining; { int len; char *ret; if (*remaining <= 0) { warning("snarf_str_field", "disk data out of synch"); return (NULL); } if (**src == '\0') { (*src)++; (*remaining)--; return (NULL); } len = strlen(*src) + 1; ret = ty_malloc(len, "snarf_str_field"); *remaining -= len; strcpy(ret, *src); (*src) += len; return (ret); } /* * Open a chunkfile. */ open_chunkfile(name) char *name; { if ((chunkfd = open(name, O_RDWR | O_CREAT, 0755)) == -1) { fatal("open_chunkfile", "could not open chunk file"); } }