ref: 17b80cbcf1d5a7c6afd74c7432ab64c100dbdc2f
dir: /sys/src/cmd/mntgen.c/
#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); }