implement ISO9660; include "sys.m"; sys: Sys; Dir, Qid, QTDIR, QTFILE, DMDIR: import sys; include "draw.m"; include "daytime.m"; daytime: Daytime; include "string.m"; str: String; include "styx.m"; styx: Styx; Rmsg, Tmsg: import styx; include "arg.m"; ISO9660: module{ init: fn(nil: ref Draw->Context, nil: list of string);}; Sectorsize: con 2048;Maxname: con 256; Enonexist: con "file does not exist";Eperm: con "permission denied";Enofile: con "no file system specified";Eauth: con "authentication failed";Ebadfid: con "invalid fid";Efidinuse: con "fid already in use";Enotdir: con "not a directory";Esyntax: con "file name syntax"; devname: string; chatty := 0;showstyx := 0;progname := "9660srv";stderr: ref Sys->FD;noplan9 := 0;nojoliet := 0;norock := 0; usage(){ sys->fprint(sys->fildes(2), "usage: %s [-rabc] [-9JR] [-s] cd_device dir\n", progname); raise "fail:usage";} init(nil: ref Draw->Context, args: list of string){ sys = load Sys Sys->PATH; sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil); stderr = sys->fildes(2); if(args != nil) progname = hd args; styx = load Styx Styx->PATH; if(styx == nil) noload(Styx->PATH); styx->init(); if(args != nil) progname = hd args; mountopt := Sys->MREPL; copt := 0; stdio := 0; arg := load Arg Arg->PATH; if(arg == nil) noload(Arg->PATH); arg->init(args); while((c := arg->opt()) != 0) case c { 'v' or 'D' => chatty = 1; showstyx = 1; 'r' => mountopt = Sys->MREPL; 'a' => mountopt = Sys->MAFTER; 'b' => mountopt = Sys->MBEFORE; 'c' => copt = Sys->MCREATE; 's' => stdio = 1; '9' => noplan9 = 1; 'J' => nojoliet = 1; 'R' => norock = 1; * => usage(); } args = arg->argv(); arg = nil; if(args == nil || tl args == nil) usage(); what := hd args; mountpt := hd tl args; daytime = load Daytime Daytime->PATH; if(daytime == nil) noload(Daytime->PATH); iobufinit(Sectorsize); pip := array[2] of ref Sys->FD; if(stdio){ pip[0] = sys->fildes(0); pip[1] = sys->fildes(1); }else if(sys->pipe(pip) < 0) error(sys->sprint("can't create pipe: %r")); devname = what; sync := chan of int; spawn fileserve(pip[1], sync); <-sync; if(sys->mount(pip[0], nil, mountpt, mountopt|copt, nil) < 0) { sys->fprint(sys->fildes(2), "%s: mount %s %s failed: %r\n", progname, what, mountpt); exit; }} noload(s: string){ sys->fprint(sys->fildes(2), "%s: can't load %s: %r\n", progname, s); raise "fail:load";} error(p: string){ sys->fprint(sys->fildes(2), "9660srv: %s\n", p); raise "fail:error";} fileserve(rfd: ref Sys->FD, sync: chan of int){ sys->pctl(Sys->NEWFD|Sys->FORKNS, list of {2, rfd.fd}); rfd = sys->fildes(rfd.fd); stderr = sys->fildes(2); sync <-= 1; while((m := Tmsg.read(rfd, 0)) != nil){ if(showstyx) chat(sys->sprint("%s...", m.text())); r: ref Rmsg; pick t := m { Readerror => error(sys->sprint("mount read error: %s", t.error)); Version => r = rversion(t); Auth => r = rauth(t); Flush => r = rflush(t); Attach => r = rattach(t); Walk => r = rwalk(t); Open => r = ropen(t); Create => r = rcreate(t); Read => r = rread(t); Write => r = rwrite(t); Clunk => r = rclunk(t); Remove => r = rremove(t); Stat => r = rstat(t); Wstat => r = rwstat(t); * => error(sys->sprint("invalid T-message tag: %d", tagof m)); } pick e := r { Error => r.tag = m.tag; } rbuf := r.pack(); if(rbuf == nil) error("bad R-message conversion"); if(showstyx) chat(r.text()+"\n"); if(styx->write(rfd, rbuf, len rbuf) != len rbuf) error(sys->sprint("connection write error: %r")); } if(chatty) chat("server end of file\n");} E(s: string): ref Rmsg.Error{ return ref Rmsg.Error(0, s);} rversion(t: ref Tmsg.Version): ref Rmsg{ (msize, version) := styx->compatible(t, Styx->MAXRPC, Styx->VERSION); return ref Rmsg.Version(t.tag, msize, version);} rauth(t: ref Tmsg.Auth): ref Rmsg{ return ref Rmsg.Error(t.tag, "authentication not required");} rflush(t: ref Tmsg.Flush): ref Rmsg{ return ref Rmsg.Flush(t.tag);} rattach(t: ref Tmsg.Attach): ref Rmsg{ dname := devname; if(t.aname != "") dname = t.aname; (dev, err) := devattach(dname, Sys->OREAD, Sectorsize); if(dev == nil) return E(err); xf := Xfs.new(dev); root := cleanfid(t.fid); root.qid = Sys->Qid(big 0, 0, Sys->QTDIR); root.xf = xf; err = root.attach(); if(err != nil){ clunkfid(t.fid); return E(err); } xf.rootqid = root.qid; return ref Rmsg.Attach(t.tag, root.qid);} walk1(f: ref Xfile, name: string): string{ if(!(f.qid.qtype & Sys->QTDIR)) return Enotdir; case name { "." => return nil; # nop, but shouldn't happen ".." => if(f.qid.path==f.xf.rootqid.path) return nil; return f.walkup(); * => return f.walk(name); }} rwalk(t: ref Tmsg.Walk): ref Rmsg{ f:=findfid(t.fid); if(f == nil) return E(Ebadfid); nf, sf: ref Xfile; if(t.newfid != t.fid){ nf = cleanfid(t.newfid); if(nf == nil) return E(Efidinuse); f.clone(nf); f = nf; }else sf = f.save(); qids: array of Sys->Qid; if(len t.names > 0){ qids = array[len t.names] of Sys->Qid; for(i := 0; i < len t.names; i++){ e := walk1(f, t.names[i]); if(e != nil){ if(nf != nil){ nf.clunk(); clunkfid(t.newfid); }else f.restore(sf); if(i == 0) return E(e); return ref Rmsg.Walk(t.tag, qids[0:i]); } qids[i] = f.qid; } } return ref Rmsg.Walk(t.tag, qids);} ropen(t: ref Tmsg.Open): ref Rmsg{ f := findfid(t.fid); if(f == nil) return E(Ebadfid); if(f.flags&Omodes) return E("open on open file"); e := f.open(t.mode); if(e != nil) return E(e); f.flags = openflags(t.mode); return ref Rmsg.Open(t.tag, f.qid, Styx->MAXFDATA);} rcreate(t: ref Tmsg.Create): ref Rmsg{ name := t.name; if(name == "." || name == "..") return E(Esyntax); f := findfid(t.fid); if(f == nil) return E(Ebadfid); if(f.flags&Omodes) return E("create on open file"); if(!(f.qid.qtype&Sys->QTDIR)) return E("create in non-directory"); e := f.create(name, t.perm, t.mode); if(e != nil) return E(e); f.flags = openflags(t.mode); return ref Rmsg.Create(t.tag, f.qid, Styx->MAXFDATA);} rread(t: ref Tmsg.Read): ref Rmsg{ err: string; f := findfid(t.fid); if(f == nil) return E(Ebadfid); if (!(f.flags&Oread)) return E("file not opened for reading"); if(t.count < 0 || t.offset < big 0) return E("negative offset or count"); b := array[Styx->MAXFDATA] of byte; count: int; if(f.qid.qtype & Sys->QTDIR) (count, err) = f.readdir(b, int t.offset, t.count); else (count, err) = f.read(b, int t.offset, t.count); if(err != nil) return E(err); if(count != len b) b = b[0:count]; return ref Rmsg.Read(t.tag, b);} rwrite(nil: ref Tmsg.Write): ref Rmsg{ return E(Eperm);} rclunk(t: ref Tmsg.Clunk): ref Rmsg{ f := findfid(t.fid); if(f == nil) return E(Ebadfid); f.clunk(); clunkfid(t.fid); return ref Rmsg.Clunk(t.tag);} rremove(t: ref Tmsg.Remove): ref Rmsg{ f := findfid(t.fid); if(f == nil) return E(Ebadfid); f.clunk(); clunkfid(t.fid); return E(Eperm);} rstat(t: ref Tmsg.Stat): ref Rmsg{ f := findfid(t.fid); if(f == nil) return E(Ebadfid); (dir, nil) := f.stat(); return ref Rmsg.Stat(t.tag, *dir);} rwstat(nil: ref Tmsg.Wstat): ref Rmsg{ return E(Eperm);} openflags(mode: int): int{ flags := 0; case mode & ~(Sys->OTRUNC|Sys->ORCLOSE) { Sys->OREAD => flags = Oread; Sys->OWRITE => flags = Owrite; Sys->ORDWR => flags = Oread|Owrite; } if(mode & Sys->ORCLOSE) flags |= Orclose; return flags;} chat(s: string){ if(chatty) sys->fprint(stderr, "%s", s);} Fid: adt { fid: int; file: ref Xfile;}; FIDMOD: con 127; # primefids := array[FIDMOD] of list of ref Fid; hashfid(fid: int): (ref Fid, array of list of ref Fid){ nl: list of ref Fid; hp := fids[fid%FIDMOD:]; nl = nil; for(l := hp[0]; l != nil; l = tl l){ f := hd l; if(f.fid == fid){ l = tl l; # excluding f for(; nl != nil; nl = tl nl) l = (hd nl) :: l; # put examined ones back, in order hp[0] = l; return (f, hp); } else nl = f :: nl; } return (nil, hp);} findfid(fid: int): ref Xfile{ (f, hp) := hashfid(fid); if(f == nil){ chat("unassigned fid"); return nil; } hp[0] = f :: hp[0]; return f.file;} cleanfid(fid: int): ref Xfile{ (f, hp) := hashfid(fid); if(f != nil){ chat("fid in use"); return nil; } f = ref Fid; f.fid = fid; f.file = Xfile.new(); hp[0] = f :: hp[0]; return f.file.clean();} clunkfid(fid: int){ (f, nil) := hashfid(fid); if(f != nil) f.file.clean();} ### Xfs: adt { d: ref Device; inuse: int; issusp: int; # system use sharing protocol in use? suspoff: int; # LEN_SKP, if so isplan9: int; # has Plan 9-specific directory info isrock: int; # is rock ridge rootqid: Sys->Qid; ptr: int; # tag for private data new: fn(nil: ref Device): ref Xfs; incref: fn(nil: self ref Xfs); decref: fn(nil: self ref Xfs);}; Xfile: adt { xf: ref Xfs; flags: int; qid: Sys->Qid; ptr: ref Isofile; # tag for private data new: fn(): ref Xfile; clean: fn(nil: self ref Xfile): ref Xfile; save: fn(nil: self ref Xfile): ref Xfile; restore: fn(nil: self ref Xfile, s: ref Xfile); attach: fn(nil: self ref Xfile): string;Lines 1–500 of 1504. Load more
implement ISO9660; include "sys.m"; sys: Sys; Dir, Qid, QTDIR, QTFILE, DMDIR: import sys; include "draw.m"; include "daytime.m"; daytime: Daytime; include "string.m"; str: String; include "styx.m"; styx: Styx; Rmsg, Tmsg: import styx; include "arg.m"; ISO9660: module { init: fn(nil: ref Draw->Context, nil: list of string); }; Sectorsize: con 2048; Maxname: con 256; Enonexist: con "file does not exist"; Eperm: con "permission denied"; Enofile: con "no file system specified"; Eauth: con "authentication failed"; Ebadfid: con "invalid fid"; Efidinuse: con "fid already in use"; Enotdir: con "not a directory"; Esyntax: con "file name syntax"; devname: string; chatty := 0; showstyx := 0; progname := "9660srv"; stderr: ref Sys->FD; noplan9 := 0; nojoliet := 0; norock := 0; usage() { sys->fprint(sys->fildes(2), "usage: %s [-rabc] [-9JR] [-s] cd_device dir\n", progname); raise "fail:usage"; } init(nil: ref Draw->Context, args: list of string) { sys = load Sys Sys->PATH; sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil); stderr = sys->fildes(2); if(args != nil) progname = hd args; styx = load Styx Styx->PATH; if(styx == nil) noload(Styx->PATH); styx->init(); if(args != nil) progname = hd args; mountopt := Sys->MREPL; copt := 0; stdio := 0; arg := load Arg Arg->PATH; if(arg == nil) noload(Arg->PATH); arg->init(args); while((c := arg->opt()) != 0) case c { 'v' or 'D' => chatty = 1; showstyx = 1; 'r' => mountopt = Sys->MREPL; 'a' => mountopt = Sys->MAFTER; 'b' => mountopt = Sys->MBEFORE; 'c' => copt = Sys->MCREATE; 's' => stdio = 1; '9' => noplan9 = 1; 'J' => nojoliet = 1; 'R' => norock = 1; * => usage(); } args = arg->argv(); arg = nil; if(args == nil || tl args == nil) usage(); what := hd args; mountpt := hd tl args; daytime = load Daytime Daytime->PATH; if(daytime == nil) noload(Daytime->PATH); iobufinit(Sectorsize); pip := array[2] of ref Sys->FD; if(stdio){ pip[0] = sys->fildes(0); pip[1] = sys->fildes(1); }else if(sys->pipe(pip) < 0) error(sys->sprint("can't create pipe: %r")); devname = what; sync := chan of int; spawn fileserve(pip[1], sync); <-sync; if(sys->mount(pip[0], nil, mountpt, mountopt|copt, nil) < 0) { sys->fprint(sys->fildes(2), "%s: mount %s %s failed: %r\n", progname, what, mountpt); exit; } } noload(s: string) { sys->fprint(sys->fildes(2), "%s: can't load %s: %r\n", progname, s); raise "fail:load"; } error(p: string) { sys->fprint(sys->fildes(2), "9660srv: %s\n", p); raise "fail:error"; } fileserve(rfd: ref Sys->FD, sync: chan of int) { sys->pctl(Sys->NEWFD|Sys->FORKNS, list of {2, rfd.fd}); rfd = sys->fildes(rfd.fd); stderr = sys->fildes(2); sync <-= 1; while((m := Tmsg.read(rfd, 0)) != nil){ if(showstyx) chat(sys->sprint("%s...", m.text())); r: ref Rmsg; pick t := m { Readerror => error(sys->sprint("mount read error: %s", t.error)); Version => r = rversion(t); Auth => r = rauth(t); Flush => r = rflush(t); Attach => r = rattach(t); Walk => r = rwalk(t); Open => r = ropen(t); Create => r = rcreate(t); Read => r = rread(t); Write => r = rwrite(t); Clunk => r = rclunk(t); Remove => r = rremove(t); Stat => r = rstat(t); Wstat => r = rwstat(t); * => error(sys->sprint("invalid T-message tag: %d", tagof m)); } pick e := r { Error => r.tag = m.tag; } rbuf := r.pack(); if(rbuf == nil) error("bad R-message conversion"); if(showstyx) chat(r.text()+"\n"); if(styx->write(rfd, rbuf, len rbuf) != len rbuf) error(sys->sprint("connection write error: %r")); } if(chatty) chat("server end of file\n"); } E(s: string): ref Rmsg.Error { return ref Rmsg.Error(0, s); } rversion(t: ref Tmsg.Version): ref Rmsg { (msize, version) := styx->compatible(t, Styx->MAXRPC, Styx->VERSION); return ref Rmsg.Version(t.tag, msize, version); } rauth(t: ref Tmsg.Auth): ref Rmsg { return ref Rmsg.Error(t.tag, "authentication not required"); } rflush(t: ref Tmsg.Flush): ref Rmsg { return ref Rmsg.Flush(t.tag); } rattach(t: ref Tmsg.Attach): ref Rmsg { dname := devname; if(t.aname != "") dname = t.aname; (dev, err) := devattach(dname, Sys->OREAD, Sectorsize); if(dev == nil) return E(err); xf := Xfs.new(dev); root := cleanfid(t.fid); root.qid = Sys->Qid(big 0, 0, Sys->QTDIR); root.xf = xf; err = root.attach(); if(err != nil){ clunkfid(t.fid); return E(err); } xf.rootqid = root.qid; return ref Rmsg.Attach(t.tag, root.qid); } walk1(f: ref Xfile, name: string): string { if(!(f.qid.qtype & Sys->QTDIR)) return Enotdir; case name { "." => return nil; # nop, but shouldn't happen ".." => if(f.qid.path==f.xf.rootqid.path) return nil; return f.walkup(); * => return f.walk(name); } } rwalk(t: ref Tmsg.Walk): ref Rmsg { f:=findfid(t.fid); if(f == nil) return E(Ebadfid); nf, sf: ref Xfile; if(t.newfid != t.fid){ nf = cleanfid(t.newfid); if(nf == nil) return E(Efidinuse); f.clone(nf); f = nf; }else sf = f.save(); qids: array of Sys->Qid; if(len t.names > 0){ qids = array[len t.names] of Sys->Qid; for(i := 0; i < len t.names; i++){ e := walk1(f, t.names[i]); if(e != nil){ if(nf != nil){ nf.clunk(); clunkfid(t.newfid); }else f.restore(sf); if(i == 0) return E(e); return ref Rmsg.Walk(t.tag, qids[0:i]); } qids[i] = f.qid; } } return ref Rmsg.Walk(t.tag, qids); } ropen(t: ref Tmsg.Open): ref Rmsg { f := findfid(t.fid); if(f == nil) return E(Ebadfid); if(f.flags&Omodes) return E("open on open file"); e := f.open(t.mode); if(e != nil) return E(e); f.flags = openflags(t.mode); return ref Rmsg.Open(t.tag, f.qid, Styx->MAXFDATA); } rcreate(t: ref Tmsg.Create): ref Rmsg { name := t.name; if(name == "." || name == "..") return E(Esyntax); f := findfid(t.fid); if(f == nil) return E(Ebadfid); if(f.flags&Omodes) return E("create on open file"); if(!(f.qid.qtype&Sys->QTDIR)) return E("create in non-directory"); e := f.create(name, t.perm, t.mode); if(e != nil) return E(e); f.flags = openflags(t.mode); return ref Rmsg.Create(t.tag, f.qid, Styx->MAXFDATA); } rread(t: ref Tmsg.Read): ref Rmsg { err: string; f := findfid(t.fid); if(f == nil) return E(Ebadfid); if (!(f.flags&Oread)) return E("file not opened for reading"); if(t.count < 0 || t.offset < big 0) return E("negative offset or count"); b := array[Styx->MAXFDATA] of byte; count: int; if(f.qid.qtype & Sys->QTDIR) (count, err) = f.readdir(b, int t.offset, t.count); else (count, err) = f.read(b, int t.offset, t.count); if(err != nil) return E(err); if(count != len b) b = b[0:count]; return ref Rmsg.Read(t.tag, b); } rwrite(nil: ref Tmsg.Write): ref Rmsg { return E(Eperm); } rclunk(t: ref Tmsg.Clunk): ref Rmsg { f := findfid(t.fid); if(f == nil) return E(Ebadfid); f.clunk(); clunkfid(t.fid); return ref Rmsg.Clunk(t.tag); } rremove(t: ref Tmsg.Remove): ref Rmsg { f := findfid(t.fid); if(f == nil) return E(Ebadfid); f.clunk(); clunkfid(t.fid); return E(Eperm); } rstat(t: ref Tmsg.Stat): ref Rmsg { f := findfid(t.fid); if(f == nil) return E(Ebadfid); (dir, nil) := f.stat(); return ref Rmsg.Stat(t.tag, *dir); } rwstat(nil: ref Tmsg.Wstat): ref Rmsg { return E(Eperm); } openflags(mode: int): int { flags := 0; case mode & ~(Sys->OTRUNC|Sys->ORCLOSE) { Sys->OREAD => flags = Oread; Sys->OWRITE => flags = Owrite; Sys->ORDWR => flags = Oread|Owrite; } if(mode & Sys->ORCLOSE) flags |= Orclose; return flags; } chat(s: string) { if(chatty) sys->fprint(stderr, "%s", s); } Fid: adt { fid: int; file: ref Xfile; }; FIDMOD: con 127; # prime fids := array[FIDMOD] of list of ref Fid; hashfid(fid: int): (ref Fid, array of list of ref Fid) { nl: list of ref Fid; hp := fids[fid%FIDMOD:]; nl = nil; for(l := hp[0]; l != nil; l = tl l){ f := hd l; if(f.fid == fid){ l = tl l; # excluding f for(; nl != nil; nl = tl nl) l = (hd nl) :: l; # put examined ones back, in order hp[0] = l; return (f, hp); } else nl = f :: nl; } return (nil, hp); } findfid(fid: int): ref Xfile { (f, hp) := hashfid(fid); if(f == nil){ chat("unassigned fid"); return nil; } hp[0] = f :: hp[0]; return f.file; } cleanfid(fid: int): ref Xfile { (f, hp) := hashfid(fid); if(f != nil){ chat("fid in use"); return nil; } f = ref Fid; f.fid = fid; f.file = Xfile.new(); hp[0] = f :: hp[0]; return f.file.clean(); } clunkfid(fid: int) { (f, nil) := hashfid(fid); if(f != nil) f.file.clean(); } # # # Xfs: adt { d: ref Device; inuse: int; issusp: int; # system use sharing protocol in use? suspoff: int; # LEN_SKP, if so isplan9: int; # has Plan 9-specific directory info isrock: int; # is rock ridge rootqid: Sys->Qid; ptr: int; # tag for private data new: fn(nil: ref Device): ref Xfs; incref: fn(nil: self ref Xfs); decref: fn(nil: self ref Xfs); }; Xfile: adt { xf: ref Xfs; flags: int; qid: Sys->Qid; ptr: ref Isofile; # tag for private data new: fn(): ref Xfile; clean: fn(nil: self ref Xfile): ref Xfile; save: fn(nil: self ref Xfile): ref Xfile; restore: fn(nil: self ref Xfile, s: ref Xfile); attach: fn(nil: self ref Xfile): string;