implement Fsys; include "common.m"; sys : Sys; styx : Styx; acme : Acme; dat : Dat; utils : Utils; look : Look; windowm : Windowm; CHDIR, Qid, ORCLOSE, OTRUNC, OREAD, OWRITE, ORDWR, Dir : import Sys; sprint : import sys; NAMELEN, DIRLEN : import Styx; Tnop, Tsession, Terror, Tflush, Tclone, Twalk, Topen, Tcreate, Tread, Twrite, Tclunk, Tremove, Tstat, Twstat, Tattach : import Styx; Rerror : import Styx; Qdir,Qacme,Qcons,Qconsctl,Qdraw,Qeditout,Qindex,Qlabel,Qnew,QWaddr,QWbody,QWconsctl,QWctl,QWdata,QWeditout,QWevent,QWrdsel,QWwrsel,QWtag,QMAX, CHAPPEND, MAXRPC : import Dat; TRUE, FALSE : import Dat; cxfidalloc, cerr : import dat; Mntdir, Fid, Dirtab, Lock, Ref, Smsg0 : import dat; Smsg : import styx; Xfid : import Xfidm; row : import dat; Column : import Columnm; Window : import windowm; lookid : import look; warning, error : import utils; init(mods : ref Dat->Mods) { sys = mods.sys; styx = mods.styx; acme = mods.acme; dat = mods.dat; utils = mods.utils; look = mods.look; windowm = mods.windowm; } 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 ( ".", Qdir|CHDIR, 8r500|CHDIR ), Dirtab ( "acme", Qacme|CHDIR, 8r500|CHDIR ), Dirtab ( "cons", Qcons, 8r600 ), Dirtab ( "consctl", Qconsctl, 8r000 ), Dirtab ( "draw", Qdraw|CHDIR, 8r000|CHDIR ), Dirtab ( "editout", Qeditout, 8r200 ), Dirtab ( "index", Qindex, 8r400 ), Dirtab ( "label", Qlabel, 8r600 ), Dirtab ( "new", Qnew, 8r500|CHDIR ), Dirtab ( nil, 0, 0 ), }; dirtabw := array[12] of { Dirtab ( ".", Qdir|CHDIR, 8r500|CHDIR ), Dirtab ( "addr", QWaddr, 8r600 ), Dirtab ( "body", QWbody, 8r600|CHAPPEND ), Dirtab ( "ctl", QWctl, 8r600 ), Dirtab ( "consctl", QWconsctl, 8r200 ), Dirtab ( "data", QWdata, 8r600 ), Dirtab ( "editout", QWeditout, 8r200 ), Dirtab ( "event", QWevent, 8r600 ), Dirtab ( "rdsel", QWrdsel, 8r400 ), Dirtab ( "wrsel", QWwrsel, 8r200 ), Dirtab ( "tag", QWtag, 8r600|CHAPPEND ), Dirtab ( nil, 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 q.path & 16rFF; } WIN(q : Qid) : int { return ((q.path&~CHDIR)>>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, MAXRPC); if(n <= 0) { if (closing) break; error("i/o error on server channel"); } (ok, x.fcall) = styx->ConvM2S(x.buf[0:n]); if(ok < 0) error("convert error in convM2S"); if(DEBUG) utils->debug(sprint("%d:%s\n", x.tid, x.fcall.print())); if (x.fcall.Mtype == Tnop || x.fcall.Mtype == Tsession) f = nil; else f = newfid(x.fcall.fid); x.f = f; case (x.fcall.Mtype) { Tnop => x = fsysnop(x); Terror => x = fsyserror(); Tflush => x = fsysflush(x); Tclone => x = fsysclone(x, f); Twalk => x = fsyswalk(x, f); Topen => x = fsysopen(x, f); Tcreate => x = fsyscreate(x); Tread => x = fsysread(x, f); Twrite => x = fsyswrite(x); Tclunk => x = fsysclunk(x, f); Tremove => x = fsysremove(x); Tstat => x = fsysstat(x, f); Twstat => x = fsyswstat(x); Tsession => x = fsyssession(x); Tattach => x = fsysattach(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; isprint("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, "/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 : Smsg; t = nullsmsg; t.qid = t0.qid; t.count = t0.count; t.data = t0.data; t.stat = t0.stat; if(err != nil){ t.Mtype = Rerror; t.ename = err; }else t.Mtype = x.fcall.Mtype+1; t.fid = x.fcall.fid; t.Tag = x.fcall.Tag; buf := t.ConvS2M(); 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.print())); 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); } 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 (x.fcall.uname != user) return respond(x, t, Eperm); f.busy = TRUE; f.open = FALSE; f.qid = (Qid)(CHDIR|Qdir, 0); f.dir = dirtab; f.nrpart = 0; f.w = nil; t.qid = f.qid; f.mntdir = nil; id = int x.fcall.aname; 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); } fsysclone(x : ref Xfid, f : ref Fid) : ref Xfid { nf : ref Fid; t : Smsg0; if(f.open) return respond(x, t, "is open"); # BUG: check exists nf = newfid(x.fcall.newfid); 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(); return respond(x, t, nil); } fsyswalk(x : ref Xfid, f : ref Fid) : ref Xfid { t : Smsg0; c, i, id : int; qid : int; d : array of Dirtab; w : ref Window; if((f.qid.path & CHDIR) == 0) return respond(x, t, Enotdir); if(x.fcall.name == ".."){ qid = Qdir|CHDIR; id = 0; } else { # is it a numeric name? regular := 0; for(i=0; i < len x.fcall.name; i++) { c = x.fcall.name[i]; if(c<'0' || '9'Xwalk; return nil; } t.qid = f.qid; return respond(x, t, nil); } fsysopen(x : ref Xfid, f : ref Fid) : ref Xfid { t : Smsg0; m : int; # can't truncate anything, so just disregard x.fcall.mode &= ~OTRUNC; # can't execute or remove anything if(x.fcall.mode&ORCLOSE) return respond(x, t, Eperm); case(x.fcall.mode){ OREAD => m = 8r400; OWRITE => m = 8r200; ORDWR => m = 8r600; * => return respond(x, t, Eperm); } if(((f.dir[0].perm&~(CHDIR|CHAPPEND))&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.path & CHDIR){ if(x.fcall.offset % 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 = x.fcall.offset; e = x.fcall.offset+x.fcall.count; clock = getclock(); b = array[Dat->BUFSIZE] of byte; id = WIN(f.qid); n = 0; if(id > 0) d = dirtabw; else d = dirtab; k = 1; # first entry is '.' for(i=0; d[k].name!=nil && i+DIRLEN= o){ bb := dostat(WIN(x.f.qid), d[k], clock); for (kk := 0; kk < DIRLEN; kk++) b[kk+n] = bb[kk]; bb = nil; n += DIRLEN; } k++; } if(id == 0){ row.qlock.lock(); nids = 0; ids = nil; for(j=0; j= o){ k = ids[j]; dt.name = sys->sprint("%d", k); dt.qid = QID(k, CHDIR); dt.perm = CHDIR|8r700; bb := dostat(k, dt, clock); for (kk := 0; kk < DIRLEN; kk++) b[kk+n] = bb[kk]; bb = nil; n += DIRLEN; } 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); } newfid(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.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, 0, 0); n := sys->read(clockfd, cbuf, len cbuf); return int string cbuf[0:n]; } dostat(id : int, dir : Dirtab, clock : int) : array of byte { d : ref Dir; d = ref Dir; d.qid.path = QID(id, dir.qid); d.qid.vers = 0; d.mode = dir.perm; d.length = 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; buf := styx->convD2M(d); d = nil; return buf; }