summaryrefslogtreecommitdiff
path: root/appl/acme/fsys.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/acme/fsys.b')
-rw-r--r--appl/acme/fsys.b866
1 files changed, 866 insertions, 0 deletions
diff --git a/appl/acme/fsys.b b/appl/acme/fsys.b
new file mode 100644
index 00000000..65ce4982
--- /dev/null
+++ b/appl/acme/fsys.b
@@ -0,0 +1,866 @@
+implement Fsys;
+
+include "common.m";
+
+sys : Sys;
+styx : Styx;
+styxaux : Styxaux;
+acme : Acme;
+dat : Dat;
+utils : Utils;
+look : Look;
+windowm : Windowm;
+xfidm : Xfidm;
+
+QTDIR, QTFILE, QTAPPEND : import Sys;
+DMDIR, DMAPPEND, Qid, ORCLOSE, OTRUNC, OREAD, OWRITE, ORDWR, Dir : import Sys;
+sprint : import sys;
+MAXWELEM, Rerror : import Styx;
+Qdir,Qacme,Qcons,Qconsctl,Qdraw,Qeditout,Qindex,Qlabel,Qnew,QWaddr,QWbody,QWconsctl,QWctl,QWdata,QWeditout,QWevent,QWrdsel,QWwrsel,QWtag,QMAX : import Dat;
+TRUE, FALSE : import Dat;
+cxfidalloc, cerr : import dat;
+Mntdir, Fid, Dirtab, Lock, Ref, Smsg0 : import dat;
+Tmsg, Rmsg : import styx;
+msize, version, fid, uname, aname, newfid, name, mode, offset, count, setmode : import styxaux;
+Xfid : import xfidm;
+row : import dat;
+Column : import Columnm;
+Window : import windowm;
+lookid : import look;
+warning, error : import utils;
+
+init(mods : ref Dat->Mods)
+{
+ messagesize = Styx->MAXRPC;
+
+ sys = mods.sys;
+ styx = mods.styx;
+ styxaux = mods.styxaux;
+ acme = mods.acme;
+ dat = mods.dat;
+ utils = mods.utils;
+ look = mods.look;
+ windowm = mods.windowm;
+ xfidm = mods.xfidm;
+}
+
+sfd, cfd : ref Sys->FD;
+
+Nhash : con 16;
+DEBUG : con 0;
+
+fids := array[Nhash] of ref Fid;
+
+Eperm := "permission denied";
+Eexist := "file does not exist";
+Enotdir := "not a directory";
+
+dirtab := array[10] of {
+ Dirtab ( ".", QTDIR, Qdir, 8r500|DMDIR ),
+ Dirtab ( "acme", QTDIR, Qacme, 8r500|DMDIR ),
+ Dirtab ( "cons", QTFILE, Qcons, 8r600 ),
+ Dirtab ( "consctl", QTFILE, Qconsctl, 8r000 ),
+ Dirtab ( "draw", QTDIR, Qdraw, 8r000|DMDIR ),
+ Dirtab ( "editout", QTFILE, Qeditout, 8r200 ),
+ Dirtab ( "index", QTFILE, Qindex, 8r400 ),
+ Dirtab ( "label", QTFILE, Qlabel, 8r600 ),
+ Dirtab ( "new", QTDIR, Qnew, 8r500|DMDIR ),
+ Dirtab ( nil, 0, 0, 0 ),
+};
+
+dirtabw := array[12] of {
+ Dirtab ( ".", QTDIR, Qdir, 8r500|DMDIR ),
+ Dirtab ( "addr", QTFILE, QWaddr, 8r600 ),
+ Dirtab ( "body", QTAPPEND, QWbody, 8r600|DMAPPEND ),
+ Dirtab ( "ctl", QTFILE, QWctl, 8r600 ),
+ Dirtab ( "consctl", QTFILE, QWconsctl, 8r200 ),
+ Dirtab ( "data", QTFILE, QWdata, 8r600 ),
+ Dirtab ( "editout", QTFILE, QWeditout, 8r200 ),
+ Dirtab ( "event", QTFILE, QWevent, 8r600 ),
+ Dirtab ( "rdsel", QTFILE, QWrdsel, 8r400 ),
+ Dirtab ( "wrsel", QTFILE, QWwrsel, 8r200 ),
+ Dirtab ( "tag", QTAPPEND, QWtag, 8r600|DMAPPEND ),
+ Dirtab ( nil, 0, 0, 0 ),
+};
+
+Mnt : adt {
+ qlock : ref Lock;
+ id : int;
+ md : ref Mntdir;
+};
+
+mnt : Mnt;
+user : string;
+clockfd : ref Sys->FD;
+closing := 0;
+
+fsysinit()
+{
+ p : array of ref Sys->FD;
+
+ p = array[2] of ref Sys->FD;
+ if(sys->pipe(p) < 0)
+ error("can't create pipe");
+ cfd = p[0];
+ sfd = p[1];
+ clockfd = sys->open("/dev/time", Sys->OREAD);
+ user = utils->getuser();
+ if (user == nil)
+ user = "Wile. E. Coyote";
+ mnt.qlock = Lock.init();
+ mnt.id = 0;
+ spawn fsysproc();
+}
+
+fsyscfd() : int
+{
+ return cfd.fd;
+}
+
+QID(w, q : int) : int
+{
+ return (w<<8)|q;
+}
+
+FILE(q : Qid) : int
+{
+ return int q.path & 16rFF;
+}
+
+WIN(q : Qid) : int
+{
+ return (int q.path>>8) & 16rFFFFFF;
+}
+
+# nullsmsg : Smsg;
+nullsmsg0 : Smsg0;
+
+fsysproc()
+{
+ n, ok : int;
+ x : ref Xfid;
+ f : ref Fid;
+ t : Smsg0;
+
+ acme->fsyspid = sys->pctl(0, nil);
+ x = nil;
+ for(;;){
+ if(x == nil){
+ cxfidalloc <-= nil;
+ x = <-cxfidalloc;
+ }
+ n = sys->read(sfd, x.buf, messagesize);
+ if(n <= 0) {
+ if (closing)
+ break;
+ error("i/o error on server channel");
+ }
+ (ok, x.fcall) = Tmsg.unpack(x.buf[0:n]);
+ if(ok < 0)
+ error("convert error in convM2S");
+ if(DEBUG)
+ utils->debug(sprint("%d:%s\n", x.tid, x.fcall.text()));
+ pick fc := x.fcall {
+ Version =>
+ f = nil;
+ Auth =>
+ f = nil;
+ * =>
+ f = allocfid(fid(x.fcall));
+ }
+ x.f = f;
+ pick fc := x.fcall {
+ Readerror => x = fsyserror();
+ Flush => x = fsysflush(x);
+ Version => x = fsysversion(x);
+ Auth => x = fsysauth(x);
+ Attach => x = fsysattach(x, f);
+ Walk => x = fsyswalk(x, f);
+ Open => x = fsysopen(x, f);
+ Create => x = fsyscreate(x);
+ Read => x = fsysread(x, f);
+ Write => x = fsyswrite(x);
+ Clunk => x = fsysclunk(x, f);
+ Remove => x = fsysremove(x);
+ Stat => x = fsysstat(x, f);
+ Wstat => x = fsyswstat(x);
+ # Clone => x = fsysclone(x, f);
+ * =>
+ x = respond(x, t, "bad fcall type");
+ }
+ }
+}
+
+fsysaddid(dir : string, ndir : int, incl : array of string, nincl : int) : ref Mntdir
+{
+ m : ref Mntdir;
+ id : int;
+
+ mnt.qlock.lock();
+ id = ++mnt.id;
+ m = ref Mntdir;
+ m.id = id;
+ m.dir = dir;
+ m.refs = 1; # one for Command, one will be incremented in attach
+ m.ndir = ndir;
+ m.next = mnt.md;
+ m.incl = incl;
+ m.nincl = nincl;
+ mnt.md = m;
+ mnt.qlock.unlock();
+ return m;
+}
+
+fsysdelid(idm : ref Mntdir)
+{
+ m, prev : ref Mntdir;
+ i : int;
+
+ if(idm == nil)
+ return;
+ mnt.qlock.lock();
+ if(--idm.refs > 0){
+ mnt.qlock.unlock();
+ return;
+ }
+ prev = nil;
+ for(m=mnt.md; m != nil; m=m.next){
+ if(m == idm){
+ if(prev != nil)
+ prev.next = m.next;
+ else
+ mnt.md = m.next;
+ for(i=0; i<m.nincl; i++)
+ m.incl[i] = nil;
+ m.incl = nil;
+ m.dir = nil;
+ m = nil;
+ mnt.qlock.unlock();
+ return;
+ }
+ prev = m;
+ }
+ mnt.qlock.unlock();
+ buf := sys->sprint("fsysdelid: can't find id %d\n", idm.id);
+ cerr <-= buf;
+}
+
+#
+# Called only in exec.l:run(), from a different FD group
+#
+fsysmount(dir : string, ndir : int, incl : array of string, nincl : int) : ref Mntdir
+{
+ m : ref Mntdir;
+
+ # close server side so don't hang if acme is half-exited
+ # sfd = nil;
+ m = fsysaddid(dir, ndir, incl, nincl);
+ buf := sys->sprint("%d", m.id);
+ if(sys->mount(cfd, nil, "/mnt/acme", Sys->MREPL, buf) < 0){
+ fsysdelid(m);
+ return nil;
+ }
+ # cfd = nil;
+ sys->bind("/mnt/acme", "/chan", Sys->MBEFORE); # was MREPL
+ if(sys->bind("/mnt/acme", "/dev", Sys->MBEFORE) < 0){
+ fsysdelid(m);
+ return nil;
+ }
+ return m;
+}
+
+fsysclose()
+{
+ closing = 1;
+ # sfd = cfd = nil;
+}
+
+respond(x : ref Xfid, t0 : Smsg0, err : string) : ref Xfid
+{
+ t : ref Rmsg;
+
+ # t = nullsmsg;
+ tag := x.fcall.tag;
+ # fid := fid(x.fcall);
+ qid := t0.qid;
+ if(err != nil)
+ t = ref Rmsg.Error(tag, err);
+ else
+ pick fc := x.fcall {
+ Readerror => t = ref Rmsg.Error(tag, err);
+ Flush => t = ref Rmsg.Flush(tag);
+ Version => t = ref Rmsg.Version(tag, t0.msize, t0.version);
+ Auth => t = ref Rmsg.Auth(tag, qid);
+ # Clone => t = ref Rmsg.Clone(tag, fid);
+ Attach => t = ref Rmsg.Attach(tag, qid);
+ Walk => t = ref Rmsg.Walk(tag, t0.qids);
+ Open => t = ref Rmsg.Open(tag, qid, t0.iounit);
+ Create => t = ref Rmsg.Create(tag, qid, 0);
+ Read => if(t0.count == len t0.data)
+ t = ref Rmsg.Read(tag, t0.data);
+ else
+ t = ref Rmsg.Read(tag, t0.data[0: t0.count]);
+ Write => t = ref Rmsg.Write(tag, t0.count);
+ Clunk => t = ref Rmsg.Clunk(tag);
+ Remove => t = ref Rmsg.Remove(tag);
+ Stat => t = ref Rmsg.Stat(tag, t0.stat);
+ Wstat => t = ref Rmsg.Wstat(tag);
+
+ }
+ # t.qid = t0.qid;
+ # t.count = t0.count;
+ # t.data = t0.data;
+ # t.stat = t0.stat;
+ # t.fid = x.fcall.fid;
+ # t.tag = x.fcall.tag;
+ buf := t.pack();
+ if(buf == nil)
+ error("convert error in convS2M");
+ if(sys->write(sfd, buf, len buf) != len buf)
+ error("write error in respond");
+ buf = nil;
+ if(DEBUG)
+ utils->debug(sprint("%d:r: %s\n", x.tid, t.text()));
+ return x;
+}
+
+# fsysnop(x : ref Xfid) : ref Xfid
+# {
+# t : Smsg0;
+#
+# return respond(x, t, nil);
+# }
+
+fsyserror() : ref Xfid
+{
+ error("sys error : Terror");
+ return nil;
+}
+
+fsyssession(x : ref Xfid) : ref Xfid
+{
+ t : Smsg0;
+
+ # BUG: should shut everybody down ??
+ t = nullsmsg0;
+ return respond(x, t, nil);
+}
+
+fsysversion(x : ref Xfid) : ref Xfid
+{
+ t : Smsg0;
+
+ pick m := x.fcall {
+ Version =>
+ (t.msize, t.version) = styx->compatible(m, messagesize, nil);
+ messagesize = t.msize;
+ return respond(x, t, nil);
+ }
+ return respond(x, t, "acme: bad version");
+
+ # ms := msize(x.fcall);
+ # if(ms < 256)
+ # return respond(x, t, "version: message size too small");
+ # t.msize = messagesize = ms;
+ # v := version(x.fcall);
+ # if(len v < 6 || v[0: 6] != "9P2000")
+ # return respond(x, t, "unrecognized 9P version");
+ # t.version = "9P2000";
+ # return respond(x, t, nil);
+}
+
+fsysauth(x : ref Xfid) : ref Xfid
+{
+ t : Smsg0;
+
+ return respond(x, t, "acme: authentication not required");
+}
+
+fsysflush(x : ref Xfid) : ref Xfid
+{
+ x.c <-= Xfidm->Xflush;
+ return nil;
+}
+
+fsysattach(x : ref Xfid, f : ref Fid) : ref Xfid
+{
+ t : Smsg0;
+ id : int;
+ m : ref Mntdir;
+
+ if (uname(x.fcall) != user)
+ return respond(x, t, Eperm);
+ f.busy = TRUE;
+ f.open = FALSE;
+ f.qid = (Qid)(big Qdir, 0, QTDIR);
+ f.dir = dirtab;
+ f.nrpart = 0;
+ f.w = nil;
+ t.qid = f.qid;
+ f.mntdir = nil;
+ id = int aname(x.fcall);
+ mnt.qlock.lock();
+ for(m=mnt.md; m != nil; m=m.next)
+ if(m.id == id){
+ f.mntdir = m;
+ m.refs++;
+ break;
+ }
+ if(m == nil)
+ cerr <-= "unknown id in attach";
+ mnt.qlock.unlock();
+ return respond(x, t, nil);
+}
+
+fsyswalk(x : ref Xfid, f : ref Fid) : ref Xfid
+{
+ t : Smsg0;
+ c, i, j, id : int;
+ path, qtype : int;
+ d, dir : array of Dirtab;
+ w : ref Window;
+ nf : ref Fid;
+
+ if(f.open)
+ return respond(x, t, "walk of open file");
+ if(fid(x.fcall) != newfid(x.fcall)){
+ nf = allocfid(newfid(x.fcall));
+ if(nf.busy)
+ return respond(x, t, "newfid already in use");
+ nf.busy = TRUE;
+ nf.open = FALSE;
+ nf.mntdir = f.mntdir;
+ if(f.mntdir != nil)
+ f.mntdir.refs++;
+ nf.dir = f.dir;
+ nf.qid = f.qid;
+ nf.w = f.w;
+ nf.nrpart = 0; # not open, so must be zero
+ if(nf.w != nil)
+ nf.w.refx.inc();
+ f = nf; # walk f
+ }
+
+ qtype = QTFILE;
+ wqids: list of Qid;
+ err := string nil;
+ id = WIN(f.qid);
+ q := f.qid;
+ names := styxaux->names(x.fcall);
+ nwname := len names;
+
+ if(nwname > 0){
+ for(i = 0; i < nwname; i++){
+ if((q.qtype & QTDIR) == 0){
+ err = Enotdir;
+ break;
+ }
+
+ name := names[i];
+ if(name == ".."){
+ path = Qdir;
+ qtype = QTDIR;
+ id = 0;
+ if(w != nil){
+ w.close();
+ w = nil;
+ }
+ if(i == MAXWELEM){
+ err = "name too long";
+ break;
+ }
+ q.qtype = qtype;
+ q.vers = 0;
+ q.path = big QID(id, path);
+ wqids = q :: wqids;
+ continue;
+ }
+
+ # is it a numeric name?
+ regular := 0;
+ for(j=0; j < len name; j++) {
+ c = name[j];
+ if(c<'0' || '9'<c) {
+ regular = 1;
+ break;
+ }
+ }
+
+ if (!regular) {
+ # yes: it's a directory
+ if(w != nil) # name has form 27/23; get out before losing w
+ break;
+ id = int name;
+ row.qlock.lock();
+ w = lookid(id, FALSE);
+ if(w == nil){
+ row.qlock.unlock();
+ break;
+ }
+ w.refx.inc();
+ path = Qdir;
+ qtype = QTDIR;
+ row.qlock.unlock();
+ dir = dirtabw;
+ if(i == MAXWELEM){
+ err = "name too long";
+ break;
+ }
+ q.qtype = qtype;
+ q.vers = 0;
+ q.path = big QID(id, path);
+ wqids = q :: wqids;
+ continue;
+ }
+ else {
+ # if(FILE(f.qid) == Qacme) # empty directory
+ # break;
+ if(name == "new"){
+ if(w != nil)
+ error("w set in walk to new");
+ cw := chan of ref Window;
+ spawn x.walk(cw);
+ w = <- cw;
+ w.refx.inc();
+ path = QID(w.id, Qdir);
+ qtype = QTDIR;
+ id = w.id;
+ dir = dirtabw;
+ # x.c <-= Xfidm->Xwalk;
+ if(i == MAXWELEM){
+ err = "name too long";
+ break;
+ }
+ q.qtype = qtype;
+ q.vers = 0;
+ q.path = big QID(id, path);
+ wqids = q :: wqids;
+ continue;
+ }
+
+ if(id == 0)
+ d = dirtab;
+ else
+ d = dirtabw;
+ k := 1; # skip '.'
+ found := 0;
+ for( ; d[k].name != nil; k++){
+ if(name == d[k].name){
+ path = d[k].qid;
+ qtype = d[k].qtype;
+ dir = d[k:];
+ if(i == MAXWELEM){
+ err = "name too long";
+ break;
+ }
+ q.qtype = qtype;
+ q.vers = 0;
+ q.path = big QID(id, path);
+ wqids = q :: wqids;
+ found = 1;
+ break;
+ }
+ }
+ if(found)
+ continue;
+ break; # file not found
+ }
+ }
+
+ if(i == 0 && err == nil)
+ err = Eexist;
+ }
+
+ nwqid := len wqids;
+ if(nwqid > 0){
+ t.qids = array[nwqid] of Qid;
+ for(i = nwqid-1; i >= 0; i--){
+ t.qids[i] = hd wqids;
+ wqids = tl wqids;
+ }
+ }
+ if(err != nil || nwqid < nwname){
+ if(nf != nil){
+ nf.busy = FALSE;
+ fsysdelid(nf.mntdir);
+ }
+ }
+ else if(nwqid == nwname){
+ if(w != nil){
+ f.w = w;
+ w = nil;
+ }
+ if(dir != nil)
+ f.dir = dir;
+ f.qid = q;
+ }
+
+ if(w != nil)
+ w.close();
+
+ return respond(x, t, err);
+}
+
+fsysopen(x : ref Xfid, f : ref Fid) : ref Xfid
+{
+ t : Smsg0;
+ m : int;
+
+ # can't truncate anything, so just disregard
+ setmode(x.fcall, mode(x.fcall)&~OTRUNC);
+ # can't execute or remove anything
+ if(mode(x.fcall)&ORCLOSE)
+ return respond(x, t, Eperm);
+ case(mode(x.fcall)){
+ OREAD =>
+ m = 8r400;
+ OWRITE =>
+ m = 8r200;
+ ORDWR =>
+ m = 8r600;
+ * =>
+ return respond(x, t, Eperm);
+ }
+ if(((f.dir[0].perm&~(DMDIR|DMAPPEND))&m) != m)
+ return respond(x, t, Eperm);
+ x.c <-= Xfidm->Xopen;
+ return nil;
+}
+
+fsyscreate(x : ref Xfid) : ref Xfid
+{
+ t : Smsg0;
+
+ return respond(x, t, Eperm);
+}
+
+idcmp(a, b : int) : int
+{
+ return a-b;
+}
+
+qsort(a : array of int, n : int)
+{
+ i, j : int;
+ t : int;
+
+ while(n > 1) {
+ i = n>>1;
+ t = a[0]; a[0] = a[i]; a[i] = t;
+ i = 0;
+ j = n;
+ for(;;) {
+ do
+ i++;
+ while(i < n && idcmp(a[i], a[0]) < 0);
+ do
+ j--;
+ while(j > 0 && idcmp(a[j], a[0]) > 0);
+ if(j < i)
+ break;
+ t = a[i]; a[i] = a[j]; a[j] = t;
+ }
+ t = a[0]; a[0] = a[j]; a[j] = t;
+ n = n-j-1;
+ if(j >= n) {
+ qsort(a, j);
+ a = a[j+1:];
+ } else {
+ qsort(a[j+1:], n);
+ n = j;
+ }
+ }
+}
+
+fsysread(x : ref Xfid, f : ref Fid) : ref Xfid
+{
+ t : Smsg0;
+ b : array of byte;
+ i, id, n, o, e, j, k, nids : int;
+ ids : array of int;
+ d : array of Dirtab;
+ dt : Dirtab;
+ c : ref Column;
+ clock : int;
+
+ b = nil;
+ if(f.qid.qtype & QTDIR){
+ # if(int offset(x.fcall) % DIRLEN)
+ # return respond(x, t, "illegal offset in directory");
+ if(FILE(f.qid) == Qacme){ # empty dir
+ t.data = nil;
+ t.count = 0;
+ respond(x, t, nil);
+ return x;
+ }
+ o = int offset(x.fcall);
+ e = int offset(x.fcall)+count(x.fcall);
+ clock = getclock();
+ b = array[messagesize] of byte;
+ id = WIN(f.qid);
+ n = 0;
+ if(id > 0)
+ d = dirtabw;
+ else
+ d = dirtab;
+ k = 1; # first entry is '.'
+ leng := 0;
+ for(i=0; d[k].name!=nil && i<e; i+=leng){
+ bb := styx->packdir(dostat(WIN(x.f.qid), d[k], clock));
+ leng = len bb;
+ for (kk := 0; kk < leng; kk++)
+ b[kk+n] = bb[kk];
+ bb = nil;
+ if(leng <= Styx->BIT16SZ)
+ break;
+ if(i >= o)
+ n += leng;
+ k++;
+ }
+ if(id == 0){
+ row.qlock.lock();
+ nids = 0;
+ ids = nil;
+ for(j=0; j<row.ncol; j++){
+ c = row.col[j];
+ for(k=0; k<c.nw; k++){
+ oids := ids;
+ ids = array[nids+1] of int;
+ ids[0:] = oids[0:nids];
+ oids = nil;
+ ids[nids++] = c.w[k].id;
+ }
+ }
+ row.qlock.unlock();
+ qsort(ids, nids);
+ j = 0;
+ for(; j<nids && i<e; i+=leng){
+ k = ids[j];
+ dt.name = sys->sprint("%d", k);
+ dt.qid = QID(k, 0);
+ dt.qtype = QTDIR;
+ dt.perm = DMDIR|8r700;
+ bb := styx->packdir(dostat(k, dt, clock));
+ leng = len bb;
+ for (kk := 0; kk < leng; kk++)
+ b[kk+n] = bb[kk];
+ bb = nil;
+ if(leng == 0)
+ break;
+ if(i >= o)
+ n += leng;
+ j++;
+ }
+ ids = nil;
+ }
+ t.data = b;
+ t.count = n;
+ respond(x, t, nil);
+ b = nil;
+ return x;
+ }
+ x.c <-= Xfidm->Xread;
+ return nil;
+}
+
+fsyswrite(x : ref Xfid) : ref Xfid
+{
+ x.c <-= Xfidm->Xwrite;
+ return nil;
+}
+
+fsysclunk(x : ref Xfid, f : ref Fid) : ref Xfid
+{
+ t : Smsg0;
+
+ fsysdelid(f.mntdir);
+ if(f.open){
+ f.busy = FALSE;
+ f.open = FALSE;
+ x.c <-= Xfidm->Xclose;
+ return nil;
+ }
+ if(f.w != nil)
+ f.w.close();
+ f.busy = FALSE;
+ f.open = FALSE;
+ return respond(x, t, nil);
+}
+
+fsysremove(x : ref Xfid) : ref Xfid
+{
+ t : Smsg0;
+
+ return respond(x, t, Eperm);
+}
+
+fsysstat(x : ref Xfid, f : ref Fid) : ref Xfid
+{
+ t : Smsg0;
+
+ t.stat = dostat(WIN(x.f.qid), f.dir[0], getclock());
+ return respond(x, t, nil);
+}
+
+fsyswstat(x : ref Xfid) : ref Xfid
+{
+ t : Smsg0;
+
+ return respond(x, t, Eperm);
+}
+
+allocfid(fid : int) : ref Fid
+{
+ f, ff : ref Fid;
+ fh : int;
+
+ ff = nil;
+ fh = fid&(Nhash-1);
+ for(f=fids[fh]; f != nil; f=f.next)
+ if(f.fid == fid)
+ return f;
+ else if(ff==nil && f.busy==FALSE)
+ ff = f;
+ if(ff != nil){
+ ff.fid = fid;
+ return ff;
+ }
+ f = ref Fid;
+ f.busy = FALSE;
+ f.rpart = array[Sys->UTFmax] of byte;
+ f.nrpart = 0;
+ f.fid = fid;
+ f.next = fids[fh];
+ fids[fh] = f;
+ return f;
+}
+
+cbuf := array[32] of byte;
+
+getclock() : int
+{
+ sys->seek(clockfd, big 0, 0);
+ n := sys->read(clockfd, cbuf, len cbuf);
+ return int string cbuf[0:n];
+}
+
+dostat(id : int, dir : Dirtab, clock : int) : Sys->Dir
+{
+ d : Dir;
+
+ d.qid.path = big QID(id, dir.qid);
+ d.qid.vers = 0;
+ d.qid.qtype = dir.qtype;
+ d.mode = dir.perm;
+ d.length = big 0; # would be nice to do better
+ d.name = dir.name;
+ d.uid = user;
+ d.gid = user;
+ d.atime = clock;
+ d.mtime = clock;
+ d.dtype = d.dev = 0;
+ return d;
+ # buf := styx->convD2M(d);
+ # d = nil;
+ # return buf;
+}