summaryrefslogtreecommitdiff
path: root/sys/src/cmd/mntgen.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/mntgen.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/mntgen.c')
-rwxr-xr-xsys/src/cmd/mntgen.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/sys/src/cmd/mntgen.c b/sys/src/cmd/mntgen.c
new file mode 100755
index 000000000..2e6a0a442
--- /dev/null
+++ b/sys/src/cmd/mntgen.c
@@ -0,0 +1,242 @@
+#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);
+}