ref: a920c765f2b4130590fb5971a50690b21664957a
dir: /appl/cmd/mntgen.b/
implement Mntgen; include "sys.m"; sys: Sys; include "draw.m"; include "styx.m"; styx: Styx; Rmsg, Tmsg: import styx; include "styxservers.m"; styxservers: Styxservers; Ebadfid, Enotfound, Eopen, Einuse: import Styxservers; Styxserver, readbytes, Navigator, Fid: import styxservers; nametree: Nametree; Tree: import nametree; Mntgen: module { init: fn(nil: ref Draw->Context, argv: list of string); }; Qroot: con big 16rfffffff; badmodule(p: string) { sys->fprint(sys->fildes(2), "cannot load %s: %r\n", p); raise "fail:bad module"; } DEBUG: con 0; Entry: adt { refcount: int; path: big; }; refcounts := array[10] of Entry; tree: ref Tree; nav: ref Navigator; uniq: int; init(nil: ref Draw->Context, nil: list of string) { sys = load Sys Sys->PATH; styx = load Styx Styx->PATH; if (styx == nil) badmodule(Styx->PATH); styx->init(); styxservers = load Styxservers Styxservers->PATH; if (styxservers == nil) badmodule(Styxservers->PATH); styxservers->init(styx); nametree = load Nametree Nametree->PATH; if (nametree == nil) badmodule(Nametree->PATH); nametree->init(); navop: chan of ref Styxservers->Navop; (tree, navop) = nametree->start(); nav = Navigator.new(navop); (tchan, srv) := Styxserver.new(sys->fildes(0), nav, Qroot); tree.create(Qroot, dir(".", Sys->DMDIR | 8r555, Qroot)); for (;;) { gm := <-tchan; if (gm == nil) { tree.quit(); exit; } e := handlemsg(gm, srv, tree); if (e != nil) srv.reply(ref Rmsg.Error(gm.tag, e)); } } walk1(c: ref Fid, name: string): string { if (name == ".."){ if (c.path != Qroot) decref(c.path); c.walk(Sys->Qid(Qroot, 0, Sys->QTDIR)); } else if (c.path == Qroot) { (d, nil) := nav.walk(c.path, name); if (d == nil) d = addentry(name); else incref(d.qid.path); c.walk(d.qid); } else return Enotfound; return nil; } handlemsg(gm: ref Styx->Tmsg, srv: ref Styxserver, nil: ref Tree): string { pick m := gm { Walk => c := srv.getfid(m.fid); if(c == nil) return Ebadfid; if(c.isopen) return Eopen; if(m.newfid != m.fid){ nc := srv.newfid(m.newfid); if(nc == nil) return Einuse; c = c.clone(nc); incref(c.path); } qids := array[len m.names] of Sys->Qid; oldpath := c.path; oldqtype := c.qtype; incref(oldpath); for (i := 0; i < len m.names; i++){ err := walk1(c, m.names[i]); if (err != nil){ if(m.newfid != m.fid){ decref(c.path); srv.delfid(c); } c.path = oldpath; c.qtype = oldqtype; if(i == 0) return err; srv.reply(ref Rmsg.Walk(m.tag, qids[0:i])); return nil; } qids[i] = Sys->Qid(c.path, 0, c.qtype); } decref(oldpath); srv.reply(ref Rmsg.Walk(m.tag, qids)); Clunk => c := srv.clunk(m); if (c != nil && c.path != Qroot) decref(c.path); * => srv.default(gm); } return nil; } addentry(name: string): ref Sys->Dir { for (i := 0; i < len refcounts; i++) if (refcounts[i].refcount == 0) break; if (i == len refcounts) { refcounts = (array[len refcounts * 2] of Entry)[0:] = refcounts; for (j := i; j < len refcounts; j++) refcounts[j].refcount = 0; } d := dir(name, Sys->DMDIR|8r555, big i | (big uniq++ << 32)); tree.create(Qroot, d); refcounts[i] = (1, d.qid.path); return ref d; } incref(q: big) { id := int q; if (id >= 0 && id < len refcounts){ refcounts[id].refcount++; } } decref(q: big) { id := int q; if (id >= 0 && id < len refcounts){ if (--refcounts[id].refcount == 0) tree.remove(refcounts[id].path); } } Blankdir: Sys->Dir; dir(name: string, perm: int, qid: big): Sys->Dir { d := Blankdir; d.name = name; d.uid = "me"; d.gid = "me"; d.qid.path = qid; if (perm & Sys->DMDIR) d.qid.qtype = Sys->QTDIR; else d.qid.qtype = Sys->QTFILE; d.mode = perm; return d; }