251 lines · 3.9 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include <mp.h>#include <libsec.h> static voidusage(void){	fprint(2, "mntgen [-s srvname] [mtpt]\n");	exits("usage");} ulong time0; typedef struct Tab Tab;struct Tab{	char *name;	vlong qid;	ulong time;	int ref;}; Tab *tab;int ntab;int mtab; static Tab*findtab(vlong path){	int i; 	for(i=0; i<ntab; i++)		if(tab[i].qid == path)			return &tab[i];	return nil;} static vlonghash(char *name){	vlong digest[MD5dlen / sizeof(vlong) + 1];	md5((uchar *)name, strlen(name), (uchar *)digest, nil);	return digest[0] & ((1ULL<<48)-1);} static voidfsopen(Req *r){	if(r->ifcall.mode != OREAD)		respond(r, "permission denied");	else		respond(r, nil);} static intdirgen(int i, Dir *d, void*){	if(i >= ntab)		return -1;	memset(d, 0, sizeof *d);	d->qid.type = QTDIR;	d->uid = estrdup9p("sys");	d->gid = estrdup9p("sys");	d->mode = DMDIR|0555;	d->length = 0;	if(i == -1){		d->name = estrdup9p("/");		d->atime = d->mtime = time0;	}else{		d->qid.path = tab[i].qid;		d->name = estrdup9p(tab[i].name);		d->atime = d->mtime = tab[i].time;	}	return 0;} static voidfsread(Req *r){	if(r->fid->qid.path == 0)		dirread9p(r, dirgen, nil);	else		r->ofcall.count = 0;	respond(r, nil);} static voidfsstat(Req *r){	Tab *t;	vlong qid; 	qid = r->fid->qid.path;	if(qid == 0)		dirgen(-1, &r->d, nil);	else{		if((t = findtab(qid)) == nil){			respond(r, "path not found (???)");			return;		}		dirgen(t-tab, &r->d, nil);	}	respond(r, nil);} static char*fswalk1(Fid *fid, char *name, void*){	int i;	Tab *t;	vlong h; 	if(fid->qid.path != 0){		/* nothing in child directory */		if(strcmp(name, "..") == 0){			if((t = findtab(fid->qid.path)) != nil)				t->ref--;			fid->qid.path = 0;			return nil;		}		return "path not found";	}	/* root */	if(strcmp(name, "..") == 0)		return nil;	for(i=0; i<ntab; i++)		if(strcmp(tab[i].name, name) == 0){			tab[i].ref++;			fid->qid.path = tab[i].qid;			return nil;		}	h = hash(name);	if(findtab(h) != nil)		return "hash collision"; 	/* create it */	if(ntab == mtab){		if(mtab == 0)			mtab = 16;		else			mtab *= 2;		tab = erealloc9p(tab, sizeof(tab[0])*mtab);	}	tab[ntab].qid = h;	fid->qid.path = tab[ntab].qid;	tab[ntab].name = estrdup9p(name);	tab[ntab].time = time(0);	tab[ntab].ref = 1;	ntab++; 	return nil;} static char*fsclone(Fid *fid, Fid*, void*){	Tab *t; 	if((t = findtab(fid->qid.path)) != nil)		t->ref++;	return nil;} static voidfswalk(Req *r){	walkandclone(r, fswalk1, fsclone, nil);} static voidfsclunk(Fid *fid){	Tab *t;	vlong qid; 	qid = fid->qid.path;	if(qid == 0)		return;	if((t = findtab(qid)) == nil){		fprint(2, "warning: cannot find %llux\n", qid);		return;	}	if(--t->ref == 0){		free(t->name);		tab[t-tab] = tab[--ntab];	}else if(t->ref < 0)		fprint(2, "warning: negative ref count for %s\n", t->name);} static voidfsattach(Req *r){	char *spec; 	spec = r->ifcall.aname;	if(spec && spec[0]){		respond(r, "invalid attach specifier");		return;	}		r->ofcall.qid = (Qid){0, 0, QTDIR};	r->fid->qid = r->ofcall.qid;	respond(r, nil);} Srv fs={.attach=	fsattach,.open=	fsopen,.read=	fsread,.stat=	fsstat,.walk=	fswalk,.destroyfid=	fsclunk}; voidmain(int argc, char **argv){	char *service; 	time0 = time(0);	service = nil;	ARGBEGIN{	case 'D':		chatty9p++;		break;	case 's':		service = EARGF(usage());		break;	default:		usage();	}ARGEND 	if(argc > 1)		usage();	postmountsrv(&fs, service, argc ? argv[0] : "/n", MAFTER);	exits(nil);}