#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <mp.h>
#include <libsec.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#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);
}
|