Plan 9 from Bell Labs’s /usr/web/sources/contrib/mycroftiv/unreleased/listfs/datfs9.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.