242 lines
3.5 KiB
C
Executable file
242 lines
3.5 KiB
C
Executable file
#include <u.h>
|
|
#include <libc.h>
|
|
#include <fcall.h>
|
|
#include <thread.h>
|
|
#include <9p.h>
|
|
#include <mp.h>
|
|
#include <libsec.h>
|
|
|
|
static void
|
|
usage(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 vlong
|
|
hash(char *name)
|
|
{
|
|
vlong digest[MD5dlen / sizeof(vlong) + 1];
|
|
md5((uchar *)name, strlen(name), (uchar *)digest, nil);
|
|
return digest[0] & ((1ULL<<48)-1);
|
|
}
|
|
|
|
static void
|
|
fsopen(Req *r)
|
|
{
|
|
if(r->ifcall.mode != OREAD)
|
|
respond(r, "permission denied");
|
|
else
|
|
respond(r, nil);
|
|
}
|
|
|
|
static int
|
|
dirgen(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 void
|
|
fsread(Req *r)
|
|
{
|
|
if(r->fid->qid.path == 0)
|
|
dirread9p(r, dirgen, nil);
|
|
else
|
|
r->ofcall.count = 0;
|
|
respond(r, nil);
|
|
}
|
|
|
|
static void
|
|
fsstat(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 void
|
|
fswalk(Req *r)
|
|
{
|
|
walkandclone(r, fswalk1, fsclone, nil);
|
|
}
|
|
|
|
static void
|
|
fsclunk(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 void
|
|
fsattach(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
|
|
};
|
|
|
|
void
|
|
main(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);
|
|
}
|