137da2899SCharles.Forsythimplement MemFS; 237da2899SCharles.Forsyth 337da2899SCharles.Forsythinclude "sys.m"; 437da2899SCharles.Forsyth sys: Sys; 537da2899SCharles.Forsyth OTRUNC, ORCLOSE, OREAD, OWRITE: import Sys; 637da2899SCharles.Forsythinclude "styx.m"; 737da2899SCharles.Forsyth styx: Styx; 837da2899SCharles.Forsyth Tmsg, Rmsg: import styx; 937da2899SCharles.Forsythinclude "styxlib.m"; 1037da2899SCharles.Forsyth styxlib: Styxlib; 1137da2899SCharles.Forsyth Styxserver: import styxlib; 1237da2899SCharles.Forsythinclude "draw.m"; 1337da2899SCharles.Forsythinclude "arg.m"; 1437da2899SCharles.Forsyth 1537da2899SCharles.ForsythMemFS: module { 1637da2899SCharles.Forsyth init: fn(ctxt: ref Draw->Context, args: list of string); 1737da2899SCharles.Forsyth}; 1837da2899SCharles.Forsyth 1937da2899SCharles.Forsyth 2037da2899SCharles.Forsythblksz : con 512; 2137da2899SCharles.ForsythEfull : con "filesystem full"; 2237da2899SCharles.Forsyth 2337da2899SCharles.ForsythMemfile : adt { 2437da2899SCharles.Forsyth name : string; 2537da2899SCharles.Forsyth owner : string; 2637da2899SCharles.Forsyth qid : Sys->Qid; 2737da2899SCharles.Forsyth perm : int; 2837da2899SCharles.Forsyth atime : int; 2937da2899SCharles.Forsyth mtime : int; 3037da2899SCharles.Forsyth nopen : int; 3137da2899SCharles.Forsyth data : array of array of byte; # allocated in blks, no holes 3237da2899SCharles.Forsyth length : int; 3337da2899SCharles.Forsyth parent : cyclic ref Memfile; # Dir entry linkage 3437da2899SCharles.Forsyth kids : cyclic ref Memfile; 3537da2899SCharles.Forsyth prev : cyclic ref Memfile; 3637da2899SCharles.Forsyth next : cyclic ref Memfile; 3737da2899SCharles.Forsyth hashnext : cyclic ref Memfile; # Qid hash linkage 3837da2899SCharles.Forsyth}; 3937da2899SCharles.Forsyth 4037da2899SCharles.ForsythQidhash : adt { 4137da2899SCharles.Forsyth buckets : array of ref Memfile; 4237da2899SCharles.Forsyth nextqid : int; 4337da2899SCharles.Forsyth new : fn () : ref Qidhash; 4437da2899SCharles.Forsyth add : fn (h : self ref Qidhash, mf : ref Memfile); 4537da2899SCharles.Forsyth remove : fn (h : self ref Qidhash, mf : ref Memfile); 4637da2899SCharles.Forsyth lookup : fn (h : self ref Qidhash, qid : Sys->Qid) : ref Memfile; 4737da2899SCharles.Forsyth}; 4837da2899SCharles.Forsyth 4937da2899SCharles.Forsythtimefd: ref Sys->FD; 5037da2899SCharles.Forsyth 5137da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string) 5237da2899SCharles.Forsyth{ 5337da2899SCharles.Forsyth sys = load Sys Sys->PATH; 5437da2899SCharles.Forsyth styx = checkload(load Styx Styx->PATH, Styx->PATH); 5537da2899SCharles.Forsyth styxlib = checkload(load Styxlib Styxlib->PATH, Styxlib->PATH); 5637da2899SCharles.Forsyth arg := checkload(load Arg Arg->PATH, Arg->PATH); 5737da2899SCharles.Forsyth 5837da2899SCharles.Forsyth amode := Sys->MREPL; 5937da2899SCharles.Forsyth maxsz := 16r7fffffff; 6037da2899SCharles.Forsyth srv := 0; 6137da2899SCharles.Forsyth mntpt := "/tmp"; 6237da2899SCharles.Forsyth 6337da2899SCharles.Forsyth arg->init(argv); 6437da2899SCharles.Forsyth arg->setusage("memfs [-s] [-rab] [-m size] [mountpoint]"); 6537da2899SCharles.Forsyth while((opt := arg->opt()) != 0) { 6637da2899SCharles.Forsyth case opt{ 6737da2899SCharles.Forsyth 's' => 6837da2899SCharles.Forsyth srv = 1; 6937da2899SCharles.Forsyth 'r' => 7037da2899SCharles.Forsyth amode = Sys->MREPL; 7137da2899SCharles.Forsyth 'a' => 7237da2899SCharles.Forsyth amode = Sys->MAFTER; 7337da2899SCharles.Forsyth 'b' => 7437da2899SCharles.Forsyth amode = Sys->MBEFORE; 7537da2899SCharles.Forsyth 'm' => 7637da2899SCharles.Forsyth maxsz = int arg->earg(); 7737da2899SCharles.Forsyth * => 7837da2899SCharles.Forsyth arg->usage(); 7937da2899SCharles.Forsyth } 8037da2899SCharles.Forsyth } 8137da2899SCharles.Forsyth argv = arg->argv(); 8237da2899SCharles.Forsyth arg = nil; 8337da2899SCharles.Forsyth if (argv != nil) 8437da2899SCharles.Forsyth mntpt = hd argv; 8537da2899SCharles.Forsyth 8637da2899SCharles.Forsyth srvfd: ref Sys->FD; 8737da2899SCharles.Forsyth mntfd: ref Sys->FD; 8837da2899SCharles.Forsyth if (srv) 8937da2899SCharles.Forsyth srvfd = sys->fildes(0); 9037da2899SCharles.Forsyth else { 9137da2899SCharles.Forsyth p := array [2] of ref Sys->FD; 9237da2899SCharles.Forsyth if (sys->pipe(p) == -1) 9337da2899SCharles.Forsyth error(sys->sprint("cannot create pipe: %r")); 9437da2899SCharles.Forsyth mntfd = p[0]; 9537da2899SCharles.Forsyth srvfd = p[1]; 9637da2899SCharles.Forsyth } 9737da2899SCharles.Forsyth styx->init(); 9837da2899SCharles.Forsyth styxlib->init(styx); 9937da2899SCharles.Forsyth timefd = sys->open("/dev/time", sys->OREAD); 10037da2899SCharles.Forsyth 10137da2899SCharles.Forsyth (tc, styxsrv) := Styxserver.new(srvfd); 10237da2899SCharles.Forsyth if (srv) 10337da2899SCharles.Forsyth memfs(maxsz, tc, styxsrv, nil); 10437da2899SCharles.Forsyth else { 10537da2899SCharles.Forsyth sync := chan of int; 10637da2899SCharles.Forsyth spawn memfs(maxsz, tc, styxsrv, sync); 10737da2899SCharles.Forsyth <-sync; 10837da2899SCharles.Forsyth if (sys->mount(mntfd, nil, mntpt, amode | Sys->MCREATE, nil) == -1) 10937da2899SCharles.Forsyth error(sys->sprint("failed to mount onto %s: %r", mntpt)); 11037da2899SCharles.Forsyth } 11137da2899SCharles.Forsyth} 11237da2899SCharles.Forsyth 11337da2899SCharles.Forsythcheckload[T](x: T, p: string): T 11437da2899SCharles.Forsyth{ 11537da2899SCharles.Forsyth if(x == nil) 11637da2899SCharles.Forsyth error(sys->sprint("cannot load %s: %r", p)); 11737da2899SCharles.Forsyth return x; 11837da2899SCharles.Forsyth} 11937da2899SCharles.Forsyth 12037da2899SCharles.Forsythstderr(): ref Sys->FD 12137da2899SCharles.Forsyth{ 12237da2899SCharles.Forsyth return sys->fildes(2); 12337da2899SCharles.Forsyth} 12437da2899SCharles.Forsyth 12537da2899SCharles.Forsytherror(e: string) 12637da2899SCharles.Forsyth{ 12737da2899SCharles.Forsyth sys->fprint(stderr(), "memfs: %s\n", e); 12837da2899SCharles.Forsyth raise "fail:error"; 12937da2899SCharles.Forsyth} 13037da2899SCharles.Forsyth 13137da2899SCharles.Forsythfreeblks: int; 13237da2899SCharles.Forsyth 13337da2899SCharles.Forsythmemfs(maxsz : int, tc : chan of ref Tmsg, srv : ref Styxserver, sync: chan of int) 13437da2899SCharles.Forsyth{ 13537da2899SCharles.Forsyth sys->pctl(Sys->NEWNS, nil); 13637da2899SCharles.Forsyth if (sync != nil) 13737da2899SCharles.Forsyth sync <-= 1; 13837da2899SCharles.Forsyth freeblks = (maxsz / blksz); 13937da2899SCharles.Forsyth qhash := Qidhash.new(); 14037da2899SCharles.Forsyth 14137da2899SCharles.Forsyth # init root 14237da2899SCharles.Forsyth root := newmf(qhash, nil, "memfs", srv.uname, 8r755 | Sys->DMDIR); 14337da2899SCharles.Forsyth root.parent = root; 14437da2899SCharles.Forsyth 14537da2899SCharles.Forsyth while((tmsg := <-tc) != nil) { 14637da2899SCharles.Forsyth# sys->print("%s\n", tmsg.text()); 14737da2899SCharles.Forsyth Msg: 14837da2899SCharles.Forsyth pick tm := tmsg { 14937da2899SCharles.Forsyth Readerror => 15037da2899SCharles.Forsyth break; 15137da2899SCharles.Forsyth Version => 15237da2899SCharles.Forsyth srv.devversion(tm); 15337da2899SCharles.Forsyth Auth => 15437da2899SCharles.Forsyth srv.devauth(tm); 15537da2899SCharles.Forsyth Flush => 15637da2899SCharles.Forsyth srv.reply(ref Rmsg.Flush(tm.tag)); 15737da2899SCharles.Forsyth Walk => 15837da2899SCharles.Forsyth (err, c, mf) := fidtomf(srv, qhash, tm.fid); 15937da2899SCharles.Forsyth if (err != "") { 16037da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 16137da2899SCharles.Forsyth continue; 16237da2899SCharles.Forsyth } 16337da2899SCharles.Forsyth nc: ref styxlib->Chan; 16437da2899SCharles.Forsyth if (tm.newfid != tm.fid) { 16537da2899SCharles.Forsyth nc = srv.clone(c, tm.newfid); 16637da2899SCharles.Forsyth if (nc == nil) { 16737da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, "fid in use")); 16837da2899SCharles.Forsyth continue; 16937da2899SCharles.Forsyth } 17037da2899SCharles.Forsyth c = nc; 17137da2899SCharles.Forsyth } 17237da2899SCharles.Forsyth qids: array of Sys->Qid; 17337da2899SCharles.Forsyth if (len tm.names > 0) { 17437da2899SCharles.Forsyth oqid := c.qid; 17537da2899SCharles.Forsyth opath := c.path; 17637da2899SCharles.Forsyth qids = array[len tm.names] of Sys->Qid; 17737da2899SCharles.Forsyth wmf := mf; 17837da2899SCharles.Forsyth for (i := 0; i < len tm.names; i++) { 17937da2899SCharles.Forsyth wmf = dirlookup(wmf, tm.names[i]); 18037da2899SCharles.Forsyth if (wmf == nil) { 18137da2899SCharles.Forsyth if (nc == nil) { 18237da2899SCharles.Forsyth c.qid = oqid; 18337da2899SCharles.Forsyth c.path = opath; 18437da2899SCharles.Forsyth } else 18537da2899SCharles.Forsyth srv.chanfree(nc); 18637da2899SCharles.Forsyth if (i == 0) 18737da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, Styxlib->Enotfound)); 18837da2899SCharles.Forsyth else 18937da2899SCharles.Forsyth srv.reply(ref Rmsg.Walk(tm.tag, qids[0:i])); 19037da2899SCharles.Forsyth break Msg; 19137da2899SCharles.Forsyth } 19237da2899SCharles.Forsyth c.qid = wmf.qid; 19337da2899SCharles.Forsyth qids[i] = wmf.qid; 19437da2899SCharles.Forsyth } 19537da2899SCharles.Forsyth } 19637da2899SCharles.Forsyth srv.reply(ref Rmsg.Walk(tm.tag, qids)); 19737da2899SCharles.Forsyth Open => 19837da2899SCharles.Forsyth (err, c, mf) := fidtomf(srv, qhash, tm.fid); 19937da2899SCharles.Forsyth if (err == "" && c.open) 20037da2899SCharles.Forsyth err = Styxlib->Eopen; 20137da2899SCharles.Forsyth if (err == "" && !modeok(tm.mode, mf.perm, c.uname, mf.owner)) 20237da2899SCharles.Forsyth err = Styxlib->Eperm; 20337da2899SCharles.Forsyth if (err == "" && (mf.perm & Sys->DMDIR) && (tm.mode & (OTRUNC|OWRITE|ORCLOSE))) 20437da2899SCharles.Forsyth err = Styxlib->Eperm; 20537da2899SCharles.Forsyth if (err == "" && (tm.mode & ORCLOSE)) { 20637da2899SCharles.Forsyth p := mf.parent; 20737da2899SCharles.Forsyth if (p == nil || !modeok(OWRITE, p.perm, c.uname, p.owner)) 20837da2899SCharles.Forsyth err = Styxlib->Eperm; 20937da2899SCharles.Forsyth } 21037da2899SCharles.Forsyth 21137da2899SCharles.Forsyth if (err != "") { 21237da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 21337da2899SCharles.Forsyth continue; 21437da2899SCharles.Forsyth } 21537da2899SCharles.Forsyth 21637da2899SCharles.Forsyth c.open = 1; 21737da2899SCharles.Forsyth c.mode = tm.mode; 21837da2899SCharles.Forsyth c.qid.vers = mf.qid.vers; 21937da2899SCharles.Forsyth mf.nopen++; 220*3f1f06c5SCharles.Forsyth if ((tm.mode & OTRUNC) && !(mf.perm & Sys->DMAPPEND)) { 22137da2899SCharles.Forsyth # OTRUNC cannot be set for a directory 22237da2899SCharles.Forsyth # always at least one blk so don't need to check fs limit 22337da2899SCharles.Forsyth freeblks += (len mf.data); 22437da2899SCharles.Forsyth mf.data = nil; 22537da2899SCharles.Forsyth freeblks--; 22637da2899SCharles.Forsyth mf.data = array[1] of {* => array [blksz] of byte}; 22737da2899SCharles.Forsyth mf.length = 0; 22837da2899SCharles.Forsyth mf.mtime = now(); 22937da2899SCharles.Forsyth } 23037da2899SCharles.Forsyth srv.reply(ref Rmsg.Open(tm.tag, mf.qid, Styx->MAXFDATA)); 23137da2899SCharles.Forsyth Create => 23237da2899SCharles.Forsyth (err, c, parent) := fidtomf(srv, qhash, tm.fid); 23337da2899SCharles.Forsyth if (err == "" && c.open) 23437da2899SCharles.Forsyth err = Styxlib->Eopen; 23537da2899SCharles.Forsyth if (err == "" && !(parent.qid.qtype & Sys->QTDIR)) 23637da2899SCharles.Forsyth err = Styxlib->Enotdir; 23737da2899SCharles.Forsyth if (err == "" && !modeok(OWRITE, parent.perm, c.uname, parent.owner)) 23837da2899SCharles.Forsyth err = Styxlib->Eperm; 23937da2899SCharles.Forsyth if (err == "" && (tm.perm & Sys->DMDIR) && (tm.mode & (OTRUNC|OWRITE|ORCLOSE))) 24037da2899SCharles.Forsyth err = Styxlib->Eperm; 24137da2899SCharles.Forsyth if (err == "" && dirlookup(parent, tm.name) != nil) 24237da2899SCharles.Forsyth err = Styxlib->Eexists; 24337da2899SCharles.Forsyth 24437da2899SCharles.Forsyth if (err != "") { 24537da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 24637da2899SCharles.Forsyth continue; 24737da2899SCharles.Forsyth } 24837da2899SCharles.Forsyth 24937da2899SCharles.Forsyth isdir := tm.perm & Sys->DMDIR; 25037da2899SCharles.Forsyth if (!isdir && freeblks <= 0) { 25137da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, Efull)); 25237da2899SCharles.Forsyth continue; 25337da2899SCharles.Forsyth } 25437da2899SCharles.Forsyth 25537da2899SCharles.Forsyth # modify perms as per Styx specification... 25637da2899SCharles.Forsyth perm : int; 25737da2899SCharles.Forsyth if (isdir) 25837da2899SCharles.Forsyth perm = (tm.perm&~8r777) | (parent.perm&tm.perm&8r777); 25937da2899SCharles.Forsyth else 26037da2899SCharles.Forsyth perm = (tm.perm&(~8r777|8r111)) | (parent.perm&tm.perm& 8r666); 26137da2899SCharles.Forsyth 26237da2899SCharles.Forsyth nmf := newmf(qhash, parent, tm.name, c.uname, perm); 26337da2899SCharles.Forsyth if (!isdir) { 26437da2899SCharles.Forsyth freeblks--; 26537da2899SCharles.Forsyth nmf.data = array[1] of {* => array [blksz] of byte}; 26637da2899SCharles.Forsyth } 26737da2899SCharles.Forsyth 26837da2899SCharles.Forsyth # link in the new MemFile 26937da2899SCharles.Forsyth nmf.next = parent.kids; 27037da2899SCharles.Forsyth if (parent.kids != nil) 27137da2899SCharles.Forsyth parent.kids.prev = nmf; 27237da2899SCharles.Forsyth parent.kids = nmf; 27337da2899SCharles.Forsyth 27437da2899SCharles.Forsyth c.open = 1; 27537da2899SCharles.Forsyth c.mode = tm.mode; 27637da2899SCharles.Forsyth c.qid = nmf.qid; 27737da2899SCharles.Forsyth nmf.nopen = 1; 27837da2899SCharles.Forsyth srv.reply(ref Rmsg.Create(tm.tag, nmf.qid, Styx->MAXFDATA)); 27937da2899SCharles.Forsyth Read => 28037da2899SCharles.Forsyth (err, c, mf) := fidtomf(srv, qhash, tm.fid); 28137da2899SCharles.Forsyth if (err == "" && !c.open) 28237da2899SCharles.Forsyth err = Styxlib->Ebadfid; 28337da2899SCharles.Forsyth 28437da2899SCharles.Forsyth if (err != "") { 28537da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 28637da2899SCharles.Forsyth continue; 28737da2899SCharles.Forsyth } 28837da2899SCharles.Forsyth data: array of byte = nil; 28937da2899SCharles.Forsyth if (mf.perm & Sys->DMDIR) 29037da2899SCharles.Forsyth data = dirdata(mf, int tm.offset, tm.count); 29137da2899SCharles.Forsyth else 29237da2899SCharles.Forsyth data = filedata(mf, int tm.offset, tm.count); 29337da2899SCharles.Forsyth mf.atime = now(); 29437da2899SCharles.Forsyth srv.reply(ref Rmsg.Read(tm.tag, data)); 29537da2899SCharles.Forsyth Write => 29637da2899SCharles.Forsyth (err, c, mf) := fidtomf(srv, qhash, tm.fid); 29737da2899SCharles.Forsyth if (c != nil && !c.open) 29837da2899SCharles.Forsyth err = Styxlib->Ebadfid; 29937da2899SCharles.Forsyth if (err == nil && (mf.perm & Sys->DMDIR)) 30037da2899SCharles.Forsyth err = Styxlib->Eperm; 30137da2899SCharles.Forsyth if (err == nil) 30237da2899SCharles.Forsyth err = writefile(mf, int tm.offset, tm.data); 30337da2899SCharles.Forsyth if (err != nil) { 30437da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 30537da2899SCharles.Forsyth continue; 30637da2899SCharles.Forsyth } 30737da2899SCharles.Forsyth srv.reply(ref Rmsg.Write(tm.tag, len tm.data)); 30837da2899SCharles.Forsyth Clunk => 30937da2899SCharles.Forsyth (err, c, mf) := fidtomf(srv, qhash, tm.fid); 31037da2899SCharles.Forsyth if (c != nil) 31137da2899SCharles.Forsyth srv.chanfree(c); 31237da2899SCharles.Forsyth if (err != nil) { 31337da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 31437da2899SCharles.Forsyth continue; 31537da2899SCharles.Forsyth } 31637da2899SCharles.Forsyth if (c.open) { 31737da2899SCharles.Forsyth if (c.mode & ORCLOSE) 31837da2899SCharles.Forsyth unlink(mf); 31937da2899SCharles.Forsyth mf.nopen--; 32037da2899SCharles.Forsyth freeblks += delfile(qhash, mf); 32137da2899SCharles.Forsyth } 32237da2899SCharles.Forsyth srv.reply(ref Rmsg.Clunk(tm.tag)); 32337da2899SCharles.Forsyth Stat => 324*3f1f06c5SCharles.Forsyth (err, nil, mf) := fidtomf(srv, qhash, tm.fid); 32537da2899SCharles.Forsyth if (err != nil) { 32637da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 32737da2899SCharles.Forsyth continue; 32837da2899SCharles.Forsyth } 32937da2899SCharles.Forsyth srv.reply(ref Rmsg.Stat(tm.tag, fileinfo(mf))); 33037da2899SCharles.Forsyth Remove => 33137da2899SCharles.Forsyth (err, c, mf) := fidtomf(srv, qhash, tm.fid); 33237da2899SCharles.Forsyth if (err != nil) { 33337da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 33437da2899SCharles.Forsyth continue; 33537da2899SCharles.Forsyth } 33637da2899SCharles.Forsyth srv.chanfree(c); 33737da2899SCharles.Forsyth parent := mf.parent; 33837da2899SCharles.Forsyth if (!modeok(OWRITE, parent.perm, c.uname, parent.owner)) 33937da2899SCharles.Forsyth err = Styxlib->Eperm; 34037da2899SCharles.Forsyth if (err == "" && (mf.perm & Sys->DMDIR) && mf.kids != nil) 34137da2899SCharles.Forsyth err = "directory not empty"; 34237da2899SCharles.Forsyth if (err == "" && mf == root) 34337da2899SCharles.Forsyth err = "root directory"; 34437da2899SCharles.Forsyth if (err != nil) { 34537da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 34637da2899SCharles.Forsyth continue; 34737da2899SCharles.Forsyth } 34837da2899SCharles.Forsyth 34937da2899SCharles.Forsyth unlink(mf); 35037da2899SCharles.Forsyth if (c.open) 35137da2899SCharles.Forsyth mf.nopen--; 35237da2899SCharles.Forsyth freeblks += delfile(qhash, mf); 35337da2899SCharles.Forsyth srv.reply(ref Rmsg.Remove(tm.tag)); 35437da2899SCharles.Forsyth Wstat => 35537da2899SCharles.Forsyth (err, c, mf) := fidtomf(srv, qhash, tm.fid); 35637da2899SCharles.Forsyth stat := tm.stat; 357*3f1f06c5SCharles.Forsyth 35837da2899SCharles.Forsyth if (err == nil && stat.name != mf.name) { 35937da2899SCharles.Forsyth parent := mf.parent; 36037da2899SCharles.Forsyth if (!modeok(OWRITE, parent.perm, c.uname, parent.owner)) 36137da2899SCharles.Forsyth err = Styxlib->Eperm; 36237da2899SCharles.Forsyth else if (dirlookup(parent, stat.name) != nil) 36337da2899SCharles.Forsyth err = Styxlib->Eexists; 36437da2899SCharles.Forsyth } 36537da2899SCharles.Forsyth if (err == nil && (stat.mode != mf.perm || stat.mtime != mf.mtime)) { 36637da2899SCharles.Forsyth if (c.uname != mf.owner) 36737da2899SCharles.Forsyth err = Styxlib->Eperm; 36837da2899SCharles.Forsyth } 36937da2899SCharles.Forsyth if (err != nil) { 37037da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, err)); 37137da2899SCharles.Forsyth continue; 37237da2899SCharles.Forsyth } 37337da2899SCharles.Forsyth isdir := mf.perm & Sys->DMDIR; 37437da2899SCharles.Forsyth if(stat.name != nil) 37537da2899SCharles.Forsyth mf.name = stat.name; 37637da2899SCharles.Forsyth if(stat.mode != ~0) 37737da2899SCharles.Forsyth mf.perm = stat.mode | isdir; 37837da2899SCharles.Forsyth if(stat.mtime != ~0) 37937da2899SCharles.Forsyth mf.mtime = stat.mtime; 38037da2899SCharles.Forsyth if(stat.uid != nil) 38137da2899SCharles.Forsyth mf.owner = stat.uid; 38237da2899SCharles.Forsyth t := now(); 38337da2899SCharles.Forsyth mf.atime = t; 38437da2899SCharles.Forsyth mf.parent.mtime = t; 38537da2899SCharles.Forsyth # not supporting group id at the moment 38637da2899SCharles.Forsyth srv.reply(ref Rmsg.Wstat(tm.tag)); 38737da2899SCharles.Forsyth Attach => 38837da2899SCharles.Forsyth c := srv.newchan(tm.fid); 38937da2899SCharles.Forsyth if (c == nil) { 39037da2899SCharles.Forsyth srv.reply(ref Rmsg.Error(tm.tag, Styxlib->Einuse)); 39137da2899SCharles.Forsyth continue; 39237da2899SCharles.Forsyth } 39337da2899SCharles.Forsyth c.uname = tm.uname; 39437da2899SCharles.Forsyth c.qid = root.qid; 39537da2899SCharles.Forsyth srv.reply(ref Rmsg.Attach(tm.tag, c.qid)); 39637da2899SCharles.Forsyth } 39737da2899SCharles.Forsyth } 39837da2899SCharles.Forsyth} 39937da2899SCharles.Forsyth 40037da2899SCharles.Forsythwritefile(mf: ref Memfile, offset: int, data: array of byte): string 40137da2899SCharles.Forsyth{ 40237da2899SCharles.Forsyth if(mf.perm & Sys->DMAPPEND) 40337da2899SCharles.Forsyth offset = mf.length; 40437da2899SCharles.Forsyth startblk := offset/blksz; 40537da2899SCharles.Forsyth nblks := ((len data + offset) - (startblk * blksz))/blksz; 40637da2899SCharles.Forsyth lastblk := startblk + nblks; 40737da2899SCharles.Forsyth need := lastblk + 1 - len mf.data; 40837da2899SCharles.Forsyth if (need > 0) { 40937da2899SCharles.Forsyth if (need > freeblks) 41037da2899SCharles.Forsyth return Efull; 41137da2899SCharles.Forsyth mf.data = (array [lastblk+1] of array of byte)[:] = mf.data; 41237da2899SCharles.Forsyth freeblks -= need; 41337da2899SCharles.Forsyth } 41437da2899SCharles.Forsyth mf.length = max(mf.length, offset + len data); 41537da2899SCharles.Forsyth 41637da2899SCharles.Forsyth # handle (possibly incomplete first block) separately 41737da2899SCharles.Forsyth offset %= blksz; 41837da2899SCharles.Forsyth end := min(blksz-offset, len data); 41937da2899SCharles.Forsyth if (mf.data[startblk] == nil) 42037da2899SCharles.Forsyth mf.data[startblk] = array [blksz] of byte; 42137da2899SCharles.Forsyth mf.data[startblk++][offset:] = data[:end]; 42237da2899SCharles.Forsyth 42337da2899SCharles.Forsyth ix := blksz - offset; 42437da2899SCharles.Forsyth while (ix < len data) { 42537da2899SCharles.Forsyth if (mf.data[startblk] == nil) 42637da2899SCharles.Forsyth mf.data[startblk] = array [blksz] of byte; 42737da2899SCharles.Forsyth end = min(ix+blksz,len data); 42837da2899SCharles.Forsyth mf.data[startblk++][:] = data[ix:end]; 42937da2899SCharles.Forsyth ix += blksz; 43037da2899SCharles.Forsyth } 43137da2899SCharles.Forsyth mf.mtime = now(); 43237da2899SCharles.Forsyth return nil; 43337da2899SCharles.Forsyth} 43437da2899SCharles.Forsyth 43537da2899SCharles.Forsythfiledata(mf: ref Memfile, offset, n: int): array of byte 43637da2899SCharles.Forsyth{ 43737da2899SCharles.Forsyth if (offset +n > mf.length) 43837da2899SCharles.Forsyth n = mf.length - offset; 43937da2899SCharles.Forsyth if (n == 0) 44037da2899SCharles.Forsyth return nil; 44137da2899SCharles.Forsyth 44237da2899SCharles.Forsyth data := array [n] of byte; 44337da2899SCharles.Forsyth startblk := offset/blksz; 44437da2899SCharles.Forsyth offset %= blksz; 44537da2899SCharles.Forsyth rn := min(blksz - offset, n); 44637da2899SCharles.Forsyth data[:] = mf.data[startblk++][offset:offset+rn]; 44737da2899SCharles.Forsyth ix := blksz - offset; 44837da2899SCharles.Forsyth while (ix < n) { 44937da2899SCharles.Forsyth rn = blksz; 45037da2899SCharles.Forsyth if (ix+rn > n) 45137da2899SCharles.Forsyth rn = n - ix; 45237da2899SCharles.Forsyth data[ix:] = mf.data[startblk++][:rn]; 45337da2899SCharles.Forsyth ix += blksz; 45437da2899SCharles.Forsyth } 45537da2899SCharles.Forsyth return data; 45637da2899SCharles.Forsyth} 45737da2899SCharles.Forsyth 45837da2899SCharles.ForsythQHSIZE: con 256; 45937da2899SCharles.ForsythQHMASK: con QHSIZE-1; 46037da2899SCharles.Forsyth 46137da2899SCharles.ForsythQidhash.new() : ref Qidhash 46237da2899SCharles.Forsyth{ 46337da2899SCharles.Forsyth qh := ref Qidhash; 46437da2899SCharles.Forsyth qh.buckets = array [QHSIZE] of ref Memfile; 46537da2899SCharles.Forsyth qh.nextqid = 0; 46637da2899SCharles.Forsyth return qh; 46737da2899SCharles.Forsyth} 46837da2899SCharles.Forsyth 46937da2899SCharles.ForsythQidhash.add(h : self ref Qidhash, mf : ref Memfile) 47037da2899SCharles.Forsyth{ 47137da2899SCharles.Forsyth path := h.nextqid++; 47237da2899SCharles.Forsyth mf.qid = Sys->Qid(big path, 0, Sys->QTFILE); 47337da2899SCharles.Forsyth bix := path & QHMASK; 47437da2899SCharles.Forsyth mf.hashnext = h.buckets[bix]; 47537da2899SCharles.Forsyth h.buckets[bix] = mf; 47637da2899SCharles.Forsyth} 47737da2899SCharles.Forsyth 47837da2899SCharles.ForsythQidhash.remove(h : self ref Qidhash, mf : ref Memfile) 47937da2899SCharles.Forsyth{ 48037da2899SCharles.Forsyth 48137da2899SCharles.Forsyth bix := int mf.qid.path & QHMASK; 48237da2899SCharles.Forsyth prev : ref Memfile; 48337da2899SCharles.Forsyth for (cur := h.buckets[bix]; cur != nil; cur = cur.hashnext) { 48437da2899SCharles.Forsyth if (cur == mf) 48537da2899SCharles.Forsyth break; 48637da2899SCharles.Forsyth prev = cur; 48737da2899SCharles.Forsyth } 48837da2899SCharles.Forsyth if (cur != nil) { 48937da2899SCharles.Forsyth if (prev != nil) 49037da2899SCharles.Forsyth prev.hashnext = cur.hashnext; 49137da2899SCharles.Forsyth else 49237da2899SCharles.Forsyth h.buckets[bix] = cur.hashnext; 49337da2899SCharles.Forsyth cur.hashnext = nil; 49437da2899SCharles.Forsyth } 49537da2899SCharles.Forsyth} 49637da2899SCharles.Forsyth 49737da2899SCharles.ForsythQidhash.lookup(h : self ref Qidhash, qid : Sys->Qid) : ref Memfile 49837da2899SCharles.Forsyth{ 49937da2899SCharles.Forsyth bix := int qid.path & QHMASK; 50037da2899SCharles.Forsyth for (mf := h.buckets[bix]; mf != nil; mf = mf.hashnext) 50137da2899SCharles.Forsyth if (mf.qid.path == qid.path) 50237da2899SCharles.Forsyth break; 50337da2899SCharles.Forsyth return mf; 50437da2899SCharles.Forsyth} 50537da2899SCharles.Forsyth 50637da2899SCharles.Forsythnewmf(qh : ref Qidhash, parent : ref Memfile, name, owner : string, perm : int) : ref Memfile 50737da2899SCharles.Forsyth{ 50837da2899SCharles.Forsyth # qid gets set by Qidhash.add() 50937da2899SCharles.Forsyth t := now(); 51037da2899SCharles.Forsyth mf := ref Memfile (name, owner, Sys->Qid(big 0,0,Sys->QTFILE), perm, t, t, 0, nil, 0, parent, nil, nil, nil, nil); 51137da2899SCharles.Forsyth qh.add(mf); 51237da2899SCharles.Forsyth if(perm & Sys->DMDIR) 51337da2899SCharles.Forsyth mf.qid.qtype = Sys->QTDIR; 51437da2899SCharles.Forsyth return mf; 51537da2899SCharles.Forsyth} 51637da2899SCharles.Forsyth 51737da2899SCharles.Forsythfidtomf(srv : ref Styxserver, qh : ref Qidhash, fid : int) : (string, ref Styxlib->Chan, ref Memfile) 51837da2899SCharles.Forsyth{ 51937da2899SCharles.Forsyth c := srv.fidtochan(fid); 52037da2899SCharles.Forsyth if (c == nil) 52137da2899SCharles.Forsyth return (Styxlib->Ebadfid, nil, nil); 52237da2899SCharles.Forsyth mf := qh.lookup(c.qid); 52337da2899SCharles.Forsyth if (mf == nil) 52437da2899SCharles.Forsyth return (Styxlib->Enotfound, c, nil); 52537da2899SCharles.Forsyth return (nil, c, mf); 52637da2899SCharles.Forsyth} 52737da2899SCharles.Forsyth 52837da2899SCharles.Forsythunlink(mf : ref Memfile) 52937da2899SCharles.Forsyth{ 53037da2899SCharles.Forsyth parent := mf.parent; 53137da2899SCharles.Forsyth if (parent == nil) 53237da2899SCharles.Forsyth return; 53337da2899SCharles.Forsyth if (mf.next != nil) 53437da2899SCharles.Forsyth mf.next.prev = mf.prev; 53537da2899SCharles.Forsyth if (mf.prev != nil) 53637da2899SCharles.Forsyth mf.prev.next = mf.next; 53737da2899SCharles.Forsyth else 53837da2899SCharles.Forsyth mf.parent.kids = mf.next; 53937da2899SCharles.Forsyth mf.parent = nil; 54037da2899SCharles.Forsyth mf.prev = nil; 54137da2899SCharles.Forsyth mf.next = nil; 54237da2899SCharles.Forsyth} 54337da2899SCharles.Forsyth 54437da2899SCharles.Forsythdelfile(qh : ref Qidhash, mf : ref Memfile) : int 54537da2899SCharles.Forsyth{ 54637da2899SCharles.Forsyth if (mf.nopen <= 0 && mf.parent == nil && mf.kids == nil 54737da2899SCharles.Forsyth && mf.prev == nil && mf.next == nil) { 54837da2899SCharles.Forsyth qh.remove(mf); 54937da2899SCharles.Forsyth nblks := len mf.data; 55037da2899SCharles.Forsyth mf.data = nil; 55137da2899SCharles.Forsyth return nblks; 55237da2899SCharles.Forsyth } 55337da2899SCharles.Forsyth return 0; 55437da2899SCharles.Forsyth} 55537da2899SCharles.Forsyth 55637da2899SCharles.Forsythdirlookup(dir : ref Memfile, name : string) : ref Memfile 55737da2899SCharles.Forsyth{ 55837da2899SCharles.Forsyth if (name == ".") 55937da2899SCharles.Forsyth return dir; 56037da2899SCharles.Forsyth if (name == "..") 56137da2899SCharles.Forsyth return dir.parent; 56237da2899SCharles.Forsyth for (mf := dir.kids; mf != nil; mf = mf.next) { 56337da2899SCharles.Forsyth if (mf.name == name) 56437da2899SCharles.Forsyth break; 56537da2899SCharles.Forsyth } 56637da2899SCharles.Forsyth return mf; 56737da2899SCharles.Forsyth} 56837da2899SCharles.Forsyth 56937da2899SCharles.Forsythaccess := array[] of {8r400, 8r200, 8r600, 8r100}; 57037da2899SCharles.Forsythmodeok(mode, perm : int, user, owner : string) : int 57137da2899SCharles.Forsyth{ 57237da2899SCharles.Forsyth if(mode >= (OTRUNC|ORCLOSE|OREAD|OWRITE)) 57337da2899SCharles.Forsyth return 0; 57437da2899SCharles.Forsyth 57537da2899SCharles.Forsyth # not handling groups! 57637da2899SCharles.Forsyth if (user != owner) 57737da2899SCharles.Forsyth perm <<= 6; 57837da2899SCharles.Forsyth 57937da2899SCharles.Forsyth if ((mode & OTRUNC) && !(perm & 8r200)) 58037da2899SCharles.Forsyth return 0; 58137da2899SCharles.Forsyth 58237da2899SCharles.Forsyth a := access[mode &3]; 58337da2899SCharles.Forsyth if ((a & perm) != a) 58437da2899SCharles.Forsyth return 0; 58537da2899SCharles.Forsyth return 1; 58637da2899SCharles.Forsyth} 58737da2899SCharles.Forsyth 58837da2899SCharles.Forsythdirdata(dir : ref Memfile, start, n : int) : array of byte 58937da2899SCharles.Forsyth{ 59037da2899SCharles.Forsyth data := array[Styx->MAXFDATA] of byte; 59137da2899SCharles.Forsyth for (k := dir.kids; start > 0 && k != nil; k = k.next) { 59237da2899SCharles.Forsyth a := styx->packdir(fileinfo(k)); 59337da2899SCharles.Forsyth start -= len a; 59437da2899SCharles.Forsyth } 59537da2899SCharles.Forsyth r := 0; 59637da2899SCharles.Forsyth for (; r < n && k != nil; k = k.next) { 59737da2899SCharles.Forsyth a := styx->packdir(fileinfo(k)); 59837da2899SCharles.Forsyth if(r+len a > n) 59937da2899SCharles.Forsyth break; 60037da2899SCharles.Forsyth data[r:] = a; 60137da2899SCharles.Forsyth r += len a; 60237da2899SCharles.Forsyth } 60337da2899SCharles.Forsyth return data[0:r]; 60437da2899SCharles.Forsyth} 60537da2899SCharles.Forsyth 60637da2899SCharles.Forsythfileinfo(f : ref Memfile) : Sys->Dir 60737da2899SCharles.Forsyth{ 60837da2899SCharles.Forsyth dir := sys->zerodir; 60937da2899SCharles.Forsyth dir.name = f.name; 61037da2899SCharles.Forsyth dir.uid = f.owner; 61137da2899SCharles.Forsyth dir.gid = "memfs"; 61237da2899SCharles.Forsyth dir.qid = f.qid; 61337da2899SCharles.Forsyth dir.mode = f.perm; 61437da2899SCharles.Forsyth dir.atime = f.atime; 61537da2899SCharles.Forsyth dir.mtime = f.mtime; 61637da2899SCharles.Forsyth dir.length = big f.length; 61737da2899SCharles.Forsyth dir.dtype = 0; 61837da2899SCharles.Forsyth dir.dev = 0; 61937da2899SCharles.Forsyth return dir; 62037da2899SCharles.Forsyth} 62137da2899SCharles.Forsyth 62237da2899SCharles.Forsythmin(a, b : int) : int 62337da2899SCharles.Forsyth{ 62437da2899SCharles.Forsyth if (a < b) 62537da2899SCharles.Forsyth return a; 62637da2899SCharles.Forsyth return b; 62737da2899SCharles.Forsyth} 62837da2899SCharles.Forsyth 62937da2899SCharles.Forsythmax(a, b : int) : int 63037da2899SCharles.Forsyth{ 63137da2899SCharles.Forsyth if (a > b) 63237da2899SCharles.Forsyth return a; 63337da2899SCharles.Forsyth return b; 63437da2899SCharles.Forsyth} 63537da2899SCharles.Forsyth 63637da2899SCharles.Forsythnow(): int 63737da2899SCharles.Forsyth{ 63837da2899SCharles.Forsyth if (timefd == nil) 63937da2899SCharles.Forsyth return 0; 64037da2899SCharles.Forsyth buf := array[128] of byte; 64137da2899SCharles.Forsyth sys->seek(timefd, big 0, 0); 64237da2899SCharles.Forsyth n := sys->read(timefd, buf, len buf); 64337da2899SCharles.Forsyth if(n < 0) 64437da2899SCharles.Forsyth return 0; 64537da2899SCharles.Forsyth 64637da2899SCharles.Forsyth t := (big string buf[0:n]) / big 1000000; 64737da2899SCharles.Forsyth return int t; 64837da2899SCharles.Forsyth} 649