#include #include #include #include #include #include #include #include #include <9p.h> #include "dbstructs.h" #define MAXDATA 8192 #define SMBUF 1024 typedef struct Record Record; struct Record { char* name; uint index; char* key; char data[MAXDATA]; uint ndata; Htab* hashtab; Hent* hashent; Frlist* hashlist; Frlist* reclist; File* file; }; void fsread(Req *r); void fswrite(Req *r); void fscreate(Req *r); void fsdestroyfile(File *f); void listcmd(char* cmd, uint len); char* hashconvert(char* hash); void printstatus(void); Srv fs = { .read= fsread, .write= fswrite, .create= fscreate, }; Record* currec; Record* lastrec; long unsigned int writecount; static char Ebad[] = "something bad happened"; static char Enomem[] = "no memory"; void listcmd(char* cmd, uint len) { Hent* tmphent; Frlist* tmpl; uint findnum; char str[256]; char* c; if(len > 255){ fprint(2, "datafs: ctl write too large!\n"); return; } if(strncmp(cmd, "next", 4) == 0){ if(currec->reclist->next != nil){ lastrec = currec; currec = currec->reclist->next->obj; currec->file->aux = currec; } return; } if(strncmp(cmd, "prev", 4) == 0){ if(currec->reclist->prev != nil){ lastrec = currec; currec = currec->reclist->prev->obj; currec->file->aux = currec; } return; } if(strncmp(cmd, "first", 5) == 0){ if(currec->reclist->first->next->obj != nil){ lastrec = currec; currec = currec->reclist->first->next->obj; currec->file->aux = currec; return; } fprint(2, "datafs: cant navigate to first in record chain\n"); return; } if(strncmp(cmd, "final", 5) == 0){ lastrec = currec; currec = currec->reclist->final->obj; if(currec == nil){ currec = lastrec; } currec->file->aux = currec; return; } if(isdigit(*cmd)){ findnum = atoi(cmd); tmpl = getnuml(findnum, currec->reclist); if(tmpl != nil){ lastrec = currec; currec = tmpl->obj; currec->file->aux = currec; } return; } if(strncmp(cmd, "key", 3) == 0){ memset(str, 0, 256); strncat(str, cmd+4, len-5); tmphent = htgetbykey(str, currec->hashtab); if(tmphent != nil){ lastrec = currec; currec = (Record*)(tmphent->owner); currec->file->aux = currec; } return; } if(strncmp(cmd, "grep", 4) == 0){ memset(str, 0, 256); strncat(str, cmd+5, len-6); tmphent = htgetbygrep(str, currec->hashtab); if(tmphent != nil){ if(tmphent->index == 0){ fprint(2, "datafs: search matched record 0, no good\n"); return; } lastrec = currec; currec = (Record*)(tmphent->owner); currec->file->aux = currec; } return; } if(strncmp(cmd, "setkey", 6) == 0){ memset(str, 0, 256); strncat(str, cmd+7, len-6); c = str; while((*c != '\n') && (c != '\0') && (c <= str+254)){ c++; } *c = '\0'; currec->key = strdup(str); currec->hashent->key = strdup(str); currec->hashlist->objname = strdup(str); currec->reclist->objname = strdup(str); return; } if(strncmp(cmd, "del", 3) == 0){ lastrec = currec; currec->reclist = reml(currec->reclist); currec = currec->reclist->obj; currec->file->aux = currec; return; } } void fsread(Req *r) { Record *rf; vlong offset; long count; char ctlread[SMBUF]; rf = r->fid->file->aux; count = r->ifcall.count; offset = r->ifcall.offset; if(strncmp(rf->name, "ctl", 3) == 0){ if((offset > 0) || (writecount == 0) || (currec == nil)){ r->ofcall.count = 0; respond(r, nil); return; } memset(ctlread, 0, SMBUF); snprint(ctlread, SMBUF, "Rec:%s index:%d key:%s datasize:%ud\n\tascii hash: %s\n", currec->name, currec->index, currec->key, currec->ndata, currec->hashent->asciihash); count = strlen(ctlread); if(r->ifcall.count < count){ respond(r, "datafs: read too small!\n"); return; } memmove(r->ofcall.data, ctlread, count); r->ofcall.count = count; respond(r, nil); return; } if(strncmp(rf->name, "hash", 4) == 0){ if((offset > 0) || (writecount == 0) || (currec == nil)){ r->ofcall.count = 0; respond(r, nil); return; } memset(ctlread, 0, SMBUF); snprint(ctlread, SMBUF, "%s", currec->hashent->asciihash); count = strlen(ctlread); if(r->ifcall.count < count){ respond(r, "datafs: read too small!\n"); return; } memmove(r->ofcall.data, ctlread, count); r->ofcall.count = count; respond(r, nil); return; } lastrec = currec; currec = rf; if(offset >= rf->ndata){ r->ofcall.count = 0; respond(r, nil); return; } if(offset+count >= rf->ndata){ count = rf->ndata - offset; } memmove(r->ofcall.data, rf->data+offset, count); r->ofcall.count = count; respond(r, nil); } void fswrite(Req *r) { Record *rf; long count; char str[256]; rf = r->fid->file->aux; if(strncmp(rf->name, "ctl", 3) == 0){ listcmd(r->ifcall.data, r->ifcall.count); r->ofcall.count = r->ifcall.count; respond(r, nil); return; } if(strncmp(rf->name, "hash", 4) == 0){ r->ofcall.count = r->ifcall.count; if(r->ifcall.count < 15){ respond(r, nil); return; } memcpy(str, r->ifcall.data, 15); rf = currec->reclist->first->next->obj; while(rf != nil){ if(strncmp(str, rf->hashent->asciihash,15) == 0){ lastrec = currec; currec = (Record*)(rf->hashent->owner); currec->file->aux = currec; respond(r, nil); return; } if(rf->reclist->next != nil){ rf = rf->reclist->next->obj; } else { respond(r, nil); return; } } respond(r, nil); return; } writecount++; lastrec = currec; currec = (Record*)emalloc9p(sizeof(Record)); memcpy(currec, rf, sizeof(Record)); count = r->ifcall.count; if(count >= MAXDATA){ respond(r, "datafs: too much data for a single record!\n"); return; } r->fid->file->length = rf->ndata; memmove(currec->data, r->ifcall.data, count); currec->ndata = count; r->ofcall.count = count; currec->index++; sprint(str, "%d%s", currec->index, currec->name); currec->key = strdup(str); currec->hashent = htput(currec->data, currec->ndata, currec->key, currec->hashtab); currec->hashlist = putl("Hent\0", sizeof(Hent), currec->key, currec->hashent, currec->hashlist); currec->reclist = putl("Record\0", sizeof(Record), currec->key, currec, currec->reclist); currec->hashent->owner = currec; r->fid->file->aux = currec; respond(r, nil); } void fscreate(Req *r) { Record *rf; File *f; if(f = createfile(r->fid->file, r->ifcall.name, r->fid->uid, r->ifcall.perm, nil)){ if(strncmp(r->ifcall.name, "ctl", 3) == 0){ respond(r, "dont try to create the ctl file\n"); return; } rf = emalloc9p(sizeof *rf); memset(rf->data, 0, MAXDATA); f->aux = rf; r->fid->file = f; r->ofcall.qid = f->qid; rf->index = 0; rf->name = strdup(r->ifcall.name); rf->key = strdup(rf->name); rf->file = f; rf->ndata = strlen(rf->key); memcpy(rf->data, rf->key, rf->ndata); rf->hashtab = htinit(rf->data, strlen(rf->data), rf->key, rf->key); rf->hashent = rf->hashtab->entlist->obj; rf->hashlist = initl("Hent\0", sizeof(Hent), rf->key, rf->hashent, rf->key); rf->reclist = initl("Record\0", sizeof(Record), rf->key, rf, rf->key); lastrec = currec; currec = rf; respond(r, nil); return; } respond(r, Ebad); } void fsdestroyfile(File *f) { Record *rf; rf = f->aux; if(rf){ free(rf->data); free(rf); } } void printstatus(void) { fprint(2, "Rec:%s index:%d key:%s datasize:%ud\n\tascii hash: %s\n", currec->name, currec->index, currec->key, currec->ndata, hashconv((char*)(currec->hashent->hval))); return; } void usage(void) { fprint(2, "usage: datafs [-D] [-s srvname] [-m mtpt]\n"); exits("usage"); } void main(int argc, char **argv) { char *addr = nil; char *srvname = nil; char *mtpt = nil; Qid q; File* ctl; Record* ctlrec; fs.tree = alloctree(nil, nil, DMDIR|0777, fsdestroyfile); q = fs.tree->root->qid; if(ctl = createfile(fs.tree->root, "ctl", getenv("user"), 0664, nil)){ ctlrec = emalloc9p(sizeof *ctlrec); ctl->aux = ctlrec; ctlrec->index = 0; ctlrec->name = strdup("ctl"); ctlrec->key = strdup(ctlrec->name); ctlrec->file = ctl; } else { sysfatal("couldnt create ctl file\n"); } if(ctl = createfile(fs.tree->root, "hash", getenv("user"), 0664, nil)){ ctlrec = emalloc9p(sizeof *ctlrec); ctl->aux = ctlrec; ctlrec->index = 0; ctlrec->name = strdup("hash"); ctlrec->key = strdup(ctlrec->name); ctlrec->file = ctl; } else { sysfatal("couldnt create hash file\n"); } currec = nil; lastrec = nil; writecount = 0; ARGBEGIN{ case 'D': chatty9p++; break; case 'a': addr = EARGF(usage()); break; case 's': srvname = EARGF(usage()); break; case 'm': mtpt = EARGF(usage()); break; default: usage(); }ARGEND; if(argc) usage(); if(chatty9p) fprint(2, "datasrv.nopipe %d srvname %s mtpt %s\n", fs.nopipe, srvname, mtpt); if(addr == nil && srvname == nil && mtpt == nil) sysfatal("must specify -a, -s, or -m option"); if(addr) listensrv(&fs, addr); if(srvname || mtpt) postmountsrv(&fs, srvname, mtpt, MREPL|MCREATE); exits(0); }