diff options
Diffstat (limited to 'appl/lib/styxconv')
| -rw-r--r-- | appl/lib/styxconv/mkfile | 6 | ||||
| -rw-r--r-- | appl/lib/styxconv/new2old.b | 640 | ||||
| -rw-r--r-- | appl/lib/styxconv/nsys.m | 51 | ||||
| -rw-r--r-- | appl/lib/styxconv/old2new.b | 480 | ||||
| -rw-r--r-- | appl/lib/styxconv/ostyx.b | 87 | ||||
| -rw-r--r-- | appl/lib/styxconv/ostyx.m | 4 |
6 files changed, 1240 insertions, 28 deletions
diff --git a/appl/lib/styxconv/mkfile b/appl/lib/styxconv/mkfile index fe4ad61e..02b28bc0 100644 --- a/appl/lib/styxconv/mkfile +++ b/appl/lib/styxconv/mkfile @@ -2,11 +2,13 @@ TARG=\ ostyx.dis\ - styxconv.dis\ - + new2old.dis\ + old2new.dis\ + MODULES=\ ostyx.m\ osys.m\ + nsys.m\ SYSMODULES=\ bufio.m\ diff --git a/appl/lib/styxconv/new2old.b b/appl/lib/styxconv/new2old.b new file mode 100644 index 00000000..36c1e91b --- /dev/null +++ b/appl/lib/styxconv/new2old.b @@ -0,0 +1,640 @@ +implement Styxconv; + +include "sys.m"; + sys: Sys; +include "osys.m"; +include "nsys.m"; +include "draw.m"; +include "styx.m"; + nstyx: Styx; + Tmsg, Rmsg: import nstyx; +include "ostyx.m"; + ostyx: OStyx; + OTmsg, ORmsg: import ostyx; +include "styxconv.m"; + +# todo: map fids > ffff into 16 bits + +DEBUG: con 1; + +Fid: adt +{ + fid: int; + isdir: int; + n: int; # size of last new client dirread request. + soff: int; # dir offset on old server. + coff: int; # dir offset on new client. + next: cyclic ref Fid; +}; + +Req: adt { + tag: int; + oldtag: int; # if it's a flush. + rp: ref Reqproc; + next: cyclic ref Req; + flushes: list of ref Rmsg.Flush; # flushes awaiting req finish. +}; + +Reqproc: adt { + newtmsg: chan of ref Tmsg; # convproc -> reqproc, once per req. + newrmsg: chan of ref Rmsg; # reqproc -> convproc, once per req + + oldtmsg: chan of ref OTmsg; # reqproc -> convproc + oldrmsg: chan of ref ORmsg; # convproc -> reqproc + + flushable: int; + + new: fn(): ref Reqproc; + rpc: fn(rp: self ref Reqproc, otm: ref OTmsg): ref ORmsg; +}; + +tags: ref Req; +avail: chan of ref Reqproc; +fids: ref Fid; +nprocs := 0; + +init() +{ + sys = load Sys Sys->PATH; + if(sys == nil) + nomod("Sys", Sys->PATH); + nstyx = load Styx Styx->PATH; + if(nstyx == nil) + nomod("Styx", Styx->PATH); + ostyx = load OStyx OStyx->PATH; + if(ostyx == nil) + nomod("OStyx", OStyx->PATH); + + ostyx->init(); + nstyx->init(); + avail = chan of ref Reqproc; +} + +styxconv(newclient: ref Sys->FD, oldsrv: ref Sys->FD) +{ + newtmsg := chan of ref Tmsg; + oldrmsg := chan of ref ORmsg; + + killpids := chan[2] of int; + spawn readnewtmsgs(killpids, newclient, newtmsg); + spawn readoldrmsgs(killpids, oldsrv, oldrmsg); + +converting: + for(;;)alt{ + ntm := <-newtmsg => + if(DEBUG) + sys->fprint(sys->fildes(2), "-> %s\n", ntm.text()); + if(ntm == nil) + break converting; + ns2os(ntm, newclient, oldsrv); + orm := <-oldrmsg => + if(DEBUG) + sys->fprint(sys->fildes(2), " <- %s\n", ostyx->rmsg2s(orm)); + if(orm == nil) + break converting; + t := looktag(orm.tag); + if(t == nil){ + warning("reply by old-server to non-existent tag"); + break; + } + pick rm := orm { + Flush => + ot := looktag(t.oldtag); + # if it's an Rflush of a request-in-progress, + # we send it to the reqproc, which + # can then clean up as it likes. + if(ot != nil){ + if(ot.rp != nil){ + if(ot.rp.flushable){ + ot.rp.oldrmsg <-= rm; + # reqproc is bound to finish after a flush + reqreply(ot, newclient, oldsrv); + }else { + # hold flush reply for later + ot.flushes = ref Rmsg.Flush(rm.tag) :: ot.flushes; + } + break; + } + deletetag(t.oldtag); + } + NRsend(newclient, ref Rmsg.Flush(rm.tag)); + deletetag(rm.tag); + * => + if(t.rp != nil){ + t.rp.oldrmsg <-= orm; + reqreply(t, newclient, oldsrv); + }else{ + os2ns(orm, newclient); + deletetag(orm.tag); + } + } + } + # kill off active reqprocs + for(; tags != nil; tags = tags.next){ + if(tags.rp != nil){ + tags.rp.oldrmsg <-= nil; + nprocs--; + } + } + # kill off idle reqprocs + while(nprocs > 0){ + rp := <-avail; + rp.newtmsg <-= nil; + nprocs--; + } + # kill off message readers + kill(<-killpids); + kill(<-killpids); +} + +# process one response from the request proc. +# request proc can respond by sending a new tmsg to the old server +# or by sending an rmsg to the new client, in which case +# it implicitly signals that it has finished processing the request. +# the actual reply might be an Rflush, signifying that +# the request has been aborted. +reqreply(t: ref Req, newclient: ref Sys->FD, oldsrv: ref Sys->FD) +{ + rp := t.rp; + alt{ + nrm := <-rp.newrmsg => + # request is done when process sends rmsg + pick rm := nrm { + Flush => + deletetag(t.tag); + } + deletetag(nrm.tag); + NRsend(newclient, nrm); + for(; t.flushes != nil; t.flushes = tl t.flushes) + NRsend(newclient, hd t.flushes); + + otm := <-rp.oldtmsg => + OTsend(oldsrv, otm); + } +} + + +# T messages: forward on, reply immediately, or start processing. +ns2os(tm0: ref Tmsg, newclient, oldsrv: ref Sys->FD) +{ + otm: ref OTmsg; + + t := ref Req(tm0.tag, -1, nil, nil, nil); + pick tm := tm0{ + Readerror => + exit; + Version => + (s, v) := nstyx->compatible(tm, nstyx->MAXRPC, nil); + NRsend(newclient, ref Rmsg.Version(tm.tag, s, v)); + return; + Auth => + NRsend(newclient, ref Rmsg.Error(tm.tag, "authorization not required")); + return; + Walk => + storetag(t); + t.rp = Reqproc.new(); + t.rp.newtmsg <-= tm; + reqreply(t, newclient, oldsrv); + return; + Attach => + otm = ref OTmsg.Attach(tm.tag, tm.fid, tm.uname, tm.aname); + Flush => + t.oldtag = tm.oldtag; + otm = ref OTmsg.Flush(tm.tag, tm.oldtag); + Open => + otm = ref OTmsg.Open(tm.tag, tm.fid, tm.mode); + Create => + otm = ref OTmsg.Create(tm.tag, tm.fid, tm.perm, tm.mode, tm.name); + Read => + fp := findfid(tm.fid); + count := tm.count; + offset := tm.offset; + if(fp != nil && fp.isdir){ + fp.n = count; + count = (count/OStyx->DIRLEN)*OStyx->DIRLEN; + if(int offset != fp.coff){ + NRsend(newclient, ref Rmsg.Error(tm.tag, "unexpected offset in dirread")); + return; + } + offset = big fp.soff; + } + otm = ref OTmsg.Read(tm.tag, tm.fid, count, offset); + Write => + otm = ref OTmsg.Write(tm.tag, tm.fid, tm.offset, tm.data); + Clunk => + otm = ref OTmsg.Clunk(tm.tag, tm.fid); + Remove => + otm = ref OTmsg.Remove(tm.tag, tm.fid); + Stat => + otm = ref OTmsg.Stat(tm.tag, tm.fid); + Wstat => + otm = ref OTmsg.Wstat(tm.tag, tm.fid, nd2od(tm.stat)); + * => + fatal("bad T message"); + } + storetag(t); + OTsend(oldsrv, otm); +} + +# R messages: old to new +os2ns(orm0: ref ORmsg, newclient: ref Sys->FD) +{ + rm: ref Rmsg; + + rm = nil; + pick orm := orm0 { + Error => + rm = ref Rmsg.Error(orm.tag, orm.err); + Flush => + rm = ref Rmsg.Flush(orm.tag); + Clone => + rm = ref Rmsg.Walk(orm.tag, nil); + Walk => + fatal("walk rmsgs should be dealt with be walkreqproc"); + Open => + setfid(orm.fid, orm.qid); + rm = ref Rmsg.Open(orm.tag, oq2nq(orm.qid), 0); + Create => + setfid(orm.fid, orm.qid); + rm = ref Rmsg.Create(orm.tag, oq2nq(orm.qid), 0); + Read => + fp := findfid(orm.fid); + data := orm.data; + if(fp != nil && fp.isdir) + data = ods2nds(data, fp.n); + fp.coff += len data; + fp.soff += len orm.data; + rm = ref Rmsg.Read(orm.tag, data); + Write => + rm = ref Rmsg.Write(orm.tag, orm.count); + Clunk => + rm = ref Rmsg.Clunk(orm.tag); + deletefid(orm.fid); + Remove => + rm = ref Rmsg.Remove(orm.tag); + deletefid(orm.fid); + Stat => + rm = ref Rmsg.Stat(orm.tag, od2nd(orm.stat)); + Wstat => + rm = ref Rmsg.Wstat(orm.tag); + Attach => + newfid(orm.fid, orm.qid.path & OSys->CHDIR); + rm = ref Rmsg.Attach(orm.tag, oq2nq(orm.qid)); + * => + fatal("bad R message"); + } + NRsend(newclient, rm); +} + +Reqproc.rpc(rp: self ref Reqproc, otm: ref OTmsg): ref ORmsg +{ + rp.oldtmsg <-= otm; + m := <-rp.oldrmsg; + if(m == nil) + exit; + return m; +} + +Reqproc.new(): ref Reqproc +{ + alt{ + rp := <-avail => + return rp; + * => + rp := ref Reqproc( + chan of ref Tmsg, + chan of ref Rmsg, + chan of ref OTmsg, + chan of ref ORmsg, + 1); + spawn reqproc(rp); + nprocs++; + return rp; + } +} + +reqproc(rp: ref Reqproc) +{ + for(;;){ + tm := <-rp.newtmsg; + if(tm == nil) + return; + rm: ref Rmsg; + pick m := tm { + Walk => + rm = walkreq(m, rp); + * => + fatal("non-walk req passed to reqproc"); + } + rp.flushable = 1; + rp.newrmsg <-= rm; + avail <-= rp; + } +} + +# note that although this is in a separate process, +# whenever it's not in Reqproc.rpc, the styxconv +# process is blocked, so although state is shared, +# there are no race conditions. +walkreq(tm: ref Tmsg.Walk, rp: ref Reqproc): ref Rmsg +{ + cloned := 0; + n := len tm.names; + if(tm.newfid != tm.fid){ + cloned = 1; + pick rm := rp.rpc(ref OTmsg.Clone(tm.tag, tm.fid, tm.newfid)) { + Clone => + ; + Error => + return ref Rmsg.Error(tm.tag, rm.err); + Flush => + return ref Rmsg.Flush(rm.tag); + * => + fatal("unexpected reply to OTmsg.Clone"); + } + cloned = 1; + } + qids := array[n] of NSys->Qid; + finalqid: OSys->Qid; + + # make sure we don't get flushed in an unwindable state. + rp.flushable = n == 1 || cloned; + for(i := 0; i < n; i++){ + pick rm := rp.rpc(ref OTmsg.Walk(tm.tag, tm.newfid, tm.names[i])) { + Walk => + qids[i] = oq2nq(rm.qid); + finalqid = rm.qid; + Flush => + if(cloned){ + rp.flushable = 0; + rp.rpc(ref OTmsg.Clunk(tm.tag, tm.newfid)); + } + return ref Rmsg.Flush(rm.tag); + Error => + if(cloned){ + rp.flushable = 0; + rp.rpc(ref OTmsg.Clunk(tm.tag, tm.newfid)); + } + if(i == 0) + return ref Rmsg.Error(tm.tag, rm.err); + return ref Rmsg.Walk(tm.tag, qids[0:i]); + } + } + if(cloned) + clonefid(tm.fid, tm.newfid); + if(n > 0) + setfid(tm.newfid, finalqid); + return ref Rmsg.Walk(tm.tag, qids); +} + +storetag(t: ref Req) +{ + t.next = tags; + tags = t; +} + +looktag(tag: int): ref Req +{ + for(t := tags; t != nil; t = t.next) + if(t.tag == tag) + return t; + return nil; +} + +deletetag(tag: int) +{ + prev: ref Req; + t := tags; + while(t != nil){ + if(t.tag == tag){ + next := t.next; + t.next = nil; + if(prev != nil) + prev.next = next; + else + tags = next; + t = next; + }else{ + prev = t; + t = t.next; + } + } +} + +newfid(fid: int, isdir: int): ref Fid +{ + f := ref Fid; + f.fid = fid; + f.isdir = isdir; + f.n = f.soff = f.coff = 0; + f.next = fids; + fids = f; + return f; +} + +clonefid(ofid: int, fid: int): ref Fid +{ + if((f := findfid(ofid)) != nil){ + nf := newfid(fid, f.isdir); + return nf; + } + warning("clone of non-existent fid"); + return newfid(fid, 0); +} + +deletefid(fid: int) +{ + lf: ref Fid; + + for(f := fids; f != nil; f = f.next){ + if(f.fid == fid){ + if(lf == nil) + fids = f.next; + else + lf.next = f.next; + return; + } + lf = f; + } +} + +findfid(fid: int): ref Fid +{ + for(f := fids; f != nil; f = f.next) + if(f.fid == fid) + return f; + return nil; +} + +setfid(fid: int, qid: OSys->Qid) +{ + f := findfid(fid); + if(f == nil){ + warning(sys->sprint("cannot find fid %d", fid)); + }else{ + f.isdir = qid.path & OSys->CHDIR; + } +} + +om2nm(om: int): int +{ + # DMDIR == CHDIR + return om; +} + +nm2om(m: int): int +{ + # DMDIR == CHDIR + return m&~(NSys->DMAPPEND|NSys->DMEXCL|NSys->DMAUTH); +} + +oq2nq(oq: OSys->Qid): NSys->Qid +{ + q: NSys->Qid; + + isdir := oq.path&OSys->CHDIR; + q.path = big (oq.path&~OSys->CHDIR); + q.vers = oq.vers; + q.qtype = 0; + if(isdir) + q.qtype |= NSys->QTDIR; + return q; +} + +nq2oq(q: NSys->Qid): OSys->Qid +{ + oq: OSys->Qid; + + isdir := q.qtype&NSys->QTDIR; + oq.path = int q.path; + oq.vers = q.vers; + if(isdir) + oq.path |= OSys->CHDIR; + return oq; +} + +od2nd(od: OSys->Dir): NSys->Dir +{ + d: NSys->Dir; + + d.name = od.name; + d.uid = od.uid; + d.gid = od.gid; + d.muid = od.uid; + d.qid = oq2nq(od.qid); + d.mode = om2nm(od.mode); + d.atime = od.atime; + d.mtime = od.mtime; + d.length = big od.length; + d.dtype = od.dtype; + d.dev = od.dev; + return d; +} + +nd2od(d: NSys->Dir): OSys->Dir +{ + od: OSys->Dir; + + od.name = d.name; + od.uid = d.uid; + od.gid = d.gid; + od.qid = nq2oq(d.qid); + od.mode = nm2om(d.mode); + od.atime = d.atime; + od.mtime = d.mtime; + od.length = int d.length; + od.dtype = d.dtype; + od.dev = d.dev; + return od; +} + +ods2nds(ob: array of byte, max: int): array of byte +{ + od: OSys->Dir; + + m := len ob; + if(m % OStyx->DIRLEN != 0) + fatal(sys->sprint("bad dir len %d", m)); + m /= OStyx->DIRLEN; + n := 0; + p := ob; + for(i := 0; i < m; i++){ + (p, od) = ostyx->convM2D(p); + d := od2nd(od); + nn := nstyx->packdirsize(d); + if(n+nn > max) # might just happen with long file names + break; + n += nn; + } + m = i; + b := array[n] of byte; + n = 0; + p = ob; + for(i = 0; i < m; i++){ + (p, od) = ostyx->convM2D(p); + d := od2nd(od); + q := nstyx->packdir(d); + nn := len q; + b[n: ] = q[0: nn]; + n += nn; + } + return b; +} + +OTsend(fd: ref Sys->FD, otm: ref OTmsg): int +{ + if(DEBUG) + sys->fprint(sys->fildes(2), " -> %s\n", ostyx->tmsg2s(otm)); + s := array[OStyx->MAXRPC] of byte; + n := ostyx->tmsg2d(otm, s); + if(n < 0) + return -1; + return sys->write(fd, s, n); +} + +NRsend(fd: ref Sys->FD, rm: ref Rmsg): int +{ + if(DEBUG) + sys->fprint(sys->fildes(2), "<- %s\n", rm.text()); + s := rm.pack(); + if(s == nil) + return -1; + return sys->write(fd, s, len s); +} + +readnewtmsgs(pidc: chan of int, newclient: ref Sys->FD, newtmsg: chan of ref Tmsg) +{ + pidc <-= sys->pctl(0, nil); + for(;;){ + newtmsg <-= Tmsg.read(newclient, nstyx->MAXRPC); + } +} + +readoldrmsgs(pidc: chan of int, oldsrv: ref Sys->FD, oldrmsg: chan of ref ORmsg) +{ + pidc <-= sys->pctl(0, nil); + for(;;){ + oldrmsg <-= ORmsg.read(oldsrv); + } +} + +warning(err: string) +{ + sys->fprint(sys->fildes(2), "warning: %s\n", err); +} + +fatal(err: string) +{ + sys->fprint(sys->fildes(2), "%s\n", err); + exit; +} + +nomod(mod: string, path: string) +{ + fatal(sys->sprint("can't load %s(%s): %r", mod, path)); +} + +kill(pid: int) +{ + sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill"); +} diff --git a/appl/lib/styxconv/nsys.m b/appl/lib/styxconv/nsys.m new file mode 100644 index 00000000..5fe267ec --- /dev/null +++ b/appl/lib/styxconv/nsys.m @@ -0,0 +1,51 @@ +NSys: module +{ + # Unique file identifier for file objects + Qid: adt + { + path: big; + vers: int; + qtype: int; + }; + + QTDIR: con 16r80; + QTAPPEND: con 16r40; + QTEXCL: con 16r20; + QTAUTH: con 16r08; + QTTMP: con 16r04; + QTFILE: con 0; + + # Return from stat and directory read + Dir: adt + { + name: string; + uid: string; + gid: string; + muid: string; + qid: Qid; + mode: int; + atime: int; + mtime: int; + length: big; + dtype: int; + dev: int; + }; + + # Maximum read which will be completed atomically; + # also the optimum block size + # + ATOMICIO: con 8192; + + OREAD: con 0; + OWRITE: con 1; + ORDWR: con 2; + OTRUNC: con 16; + ORCLOSE: con 64; + OEXCL: con 16r1000; + + DMDIR: con int 1<<31; + DMAPPEND: con int 1<<30; + DMEXCL: con int 1<<29; + DMAUTH: con int 1<<27; + DMTMP: con int 1<<26; +}; diff --git a/appl/lib/styxconv/old2new.b b/appl/lib/styxconv/old2new.b new file mode 100644 index 00000000..a9ced502 --- /dev/null +++ b/appl/lib/styxconv/old2new.b @@ -0,0 +1,480 @@ +implement Styxconv; + +include "sys.m"; + sys: Sys; +include "osys.m"; +include "nsys.m"; +include "draw.m"; +include "styx.m"; + nstyx: Styx; + Tmsg, Rmsg: import nstyx; +include "ostyx.m"; + ostyx: OStyx; + OTmsg, ORmsg: import ostyx; +include "styxconv.m"; + +DEBUG: con 0; + +# convert from old styx client to new styx server. +# more straightforward than the other way around +# because there's an almost exactly 1-1 mapping +# between message types. (the exception is Tversion, +# but we do that synchronously anyway). + +# todo: map qids > ffffffff into 32 bits. + +Msize: con nstyx->IOHDRSZ + OSys->ATOMICIO; +Fid: adt +{ + fid: int; + isdir: int; + n: int; # size of last new client dirread request. + soff: int; # dir offset on new server. + coff: int; # dir offset on old client. + next: cyclic ref Fid; + extras: array of byte; # packed old styx dir structures +}; + +Req: adt { + tag: int; + fid: int; + oldtag: int; # if it's a flush. + newfid: int; # if it's a clone + next: cyclic ref Req; +}; + +tags: ref Req; +fids: ref Fid; + +init() +{ + sys = load Sys Sys->PATH; + if(sys == nil) + nomod("Sys", Sys->PATH); + nstyx = load Styx Styx->PATH; + if(nstyx == nil) + nomod("Styx", Styx->PATH); + ostyx = load OStyx OStyx->PATH; + if(ostyx == nil) + nomod("OStyx", OStyx->PATH); + + ostyx->init(); + nstyx->init(); +} + +styxconv(oldclient, newsrv: ref Sys->FD) +{ + oldtmsg := chan of ref OTmsg; + newrmsg := chan of ref Rmsg; + + killpids := chan[2] of int; + spawn readoldtmsgs(killpids, oldclient, oldtmsg); + spawn readnewrmsgs(killpids, newsrv, newrmsg); + # XXX difficulty: what happens if the server isn't responding + # and the client hangs up? we won't know about it. + # but we don't want to know about normal t-messages + # piling up either, so we don't want to alt on oldtmsg too. + NTsend(newsrv, ref Tmsg.Version(nstyx->NOTAG, Msize, "9P2000")); + pick nrm := <-newrmsg { + Version => + if(DEBUG) + sys->fprint(sys->fildes(2), " <- %s\n", nrm.text()); + if(nrm.msize < Msize) + fatal("message size too small"); + Error => + fatal("versioning failed: " + nrm.ename); + * => + fatal("bad response to Tversion: " + nrm.text()); + } + +converting: + for(;;)alt{ + otm := <-oldtmsg => + if(DEBUG) + sys->fprint(sys->fildes(2), "-> %s\n", ostyx->tmsg2s(otm)); + if(otm == nil || tagof(otm) == tagof(OTmsg.Readerror)) + break converting; + oc2ns(otm, oldclient, newsrv); + nrm := <-newrmsg => + if(DEBUG) + sys->fprint(sys->fildes(2), " <- %s\n", nrm.text()); + if(nrm == nil || tagof(nrm) == tagof(Rmsg.Readerror)) + break converting; + t := looktag(nrm.tag); + if(t == nil){ + warning("reply by new-server to non-existent tag"); + break; + } + ns2oc(t, nrm, oldclient); + deletetag(nrm.tag); + } + + kill(<-killpids); + kill(<-killpids); +} + +# T messages: forward on or reply immediately +oc2ns(tm0: ref OTmsg, oldclient, newsrv: ref Sys->FD) +{ + ntm: ref Tmsg; + + t := ref Req(tm0.tag, -1, -1, -1, nil); + pick tm := tm0{ + Nop => + ORsend(oldclient, ref ORmsg.Nop(tm.tag)); + return; + Attach => + t.fid = tm.fid; + ntm = ref Tmsg.Attach(tm.tag, tm.fid, nstyx->NOFID, tm.uname, tm.aname); + Clone => + t.fid = tm.fid; + t.newfid = tm.newfid; + ntm = ref Tmsg.Walk(tm.tag, tm.fid, tm.newfid, nil); + Walk => + t.fid = tm.fid; + ntm = ref Tmsg.Walk(tm.tag, tm.fid, tm.fid, array[] of {tm.name}); + Flush => + t.oldtag = tm.oldtag; + ntm = ref Tmsg.Flush(tm.tag, tm.oldtag); + Open => + t.fid = tm.fid; + ntm = ref Tmsg.Open(tm.tag, tm.fid, tm.mode); + Create => + t.fid = tm.fid; + ntm = ref Tmsg.Create(tm.tag, tm.fid, tm.name, tm.perm, tm.mode); + Read => + t.fid = tm.fid; + fp := findfid(tm.fid); + count := tm.count; + offset := tm.offset; + if(fp.isdir){ + count = (count/OStyx->DIRLEN)*OStyx->DIRLEN; + # if we got some extra entries last time, + # then send 'em back this time. + extras := fp.extras; + if(len extras > 0){ + if(count > len extras) + count = len extras; + ORsend(oldclient, ref ORmsg.Read(tm.tag, t.fid, fp.extras[0:count])); + fp.extras = extras[count:]; + fp.coff += count; + return; + } + fp.n = count; + if(int offset != fp.coff){ + ORsend(oldclient, ref ORmsg.Error(tm.tag, "unexpected offset in dirread")); + return; + } + offset = big fp.soff; + } + ntm = ref Tmsg.Read(tm.tag, tm.fid, offset, count); + Write => + t.fid = tm.fid; + ntm = ref Tmsg.Write(tm.tag, tm.fid, tm.offset, tm.data); + Clunk => + t.fid = tm.fid; + ntm = ref Tmsg.Clunk(tm.tag, tm.fid); + Remove => + t.fid = tm.fid; + ntm = ref Tmsg.Remove(tm.tag, tm.fid); + Stat => + t.fid = tm.fid; + ntm = ref Tmsg.Stat(tm.tag, tm.fid); + Wstat => + t.fid = tm.fid; + ntm = ref Tmsg.Wstat(tm.tag, tm.fid, od2nd(tm.stat)); + * => + fatal("bad T message"); + } + storetag(t); + NTsend(newsrv, ntm); +} + +# R messages: new to old +ns2oc(t: ref Req, nrm0: ref Rmsg, oldclient: ref Sys->FD) +{ + rm: ref ORmsg; + pick nrm := nrm0{ + Error => + rm = ref ORmsg.Error(nrm.tag, nrm.ename); + Flush => + rm = ref ORmsg.Flush(nrm.tag); + deletetag(t.oldtag); + Walk => + if(len nrm.qids == 0){ + clonefid(t.fid, t.newfid); + rm = ref ORmsg.Clone(nrm.tag, t.fid); + }else{ + q := nrm.qids[0]; + setfid(t.fid, q); + rm = ref ORmsg.Walk(nrm.tag, t.fid, nq2oq(q)); + } + Open => + setfid(t.fid, nrm.qid); + rm = ref ORmsg.Open(nrm.tag, t.fid, nq2oq(nrm.qid)); + Create => + setfid(t.fid, nrm.qid); + rm = ref ORmsg.Create(nrm.tag, t.fid, nq2oq(nrm.qid)); + Read => + fp := findfid(t.fid); + data := nrm.data; + if(fp != nil && fp.isdir){ + data = nds2ods(data); + if(len data > fp.n){ + fp.extras = data[fp.n:]; + data = data[0:fp.n]; + } + fp.coff += len data; + fp.soff += len nrm.data; + } + rm = ref ORmsg.Read(nrm.tag, t.fid, data); + Write => + rm = ref ORmsg.Write(nrm.tag, t.fid, nrm.count); + Clunk => + deletefid(t.fid); + rm = ref ORmsg.Clunk(nrm.tag, t.fid); + Remove => + deletefid(t.fid); + rm = ref ORmsg.Remove(nrm.tag, t.fid); + Stat => + rm = ref ORmsg.Stat(nrm.tag, t.fid, nd2od(nrm.stat)); + Wstat => + rm = ref ORmsg.Wstat(nrm.tag, t.fid); + Attach => + newfid(t.fid, nrm.qid.qtype & NSys->QTDIR); + rm = ref ORmsg.Attach(nrm.tag, t.fid, nq2oq(nrm.qid)); + * => + fatal("bad R message"); + } + ORsend(oldclient, rm); +} + +storetag(t: ref Req) +{ + t.next = tags; + tags = t; +} + +looktag(tag: int): ref Req +{ + for(t := tags; t != nil; t = t.next) + if(t.tag == tag) + return t; + return nil; +} + +deletetag(tag: int) +{ + prev: ref Req; + t := tags; + while(t != nil){ + if(t.tag == tag){ + next := t.next; + t.next = nil; + if(prev != nil) + prev.next = next; + else + tags = next; + t = next; + }else{ + prev = t; + t = t.next; + } + } +} + +newfid(fid: int, isdir: int): ref Fid +{ + f := ref Fid; + f.fid = fid; + f.isdir = isdir; + f.n = f.soff = f.coff = 0; + f.next = fids; + fids = f; + return f; +} + +clonefid(ofid: int, fid: int): ref Fid +{ + if((f := findfid(ofid)) != nil) + return newfid(fid, f.isdir); + warning("clone of non-existent fid"); + return newfid(fid, 0); +} + +deletefid(fid: int) +{ + lf: ref Fid; + + for(f := fids; f != nil; f = f.next){ + if(f.fid == fid){ + if(lf == nil) + fids = f.next; + else + lf.next = f.next; + return; + } + lf = f; + } +} + +findfid(fid: int): ref Fid +{ + for(f := fids; f != nil && f.fid != fid; f = f.next) + ; + return f; +} + +setfid(fid: int, qid: NSys->Qid) +{ + if((f := findfid(fid)) != nil) + f.isdir = qid.qtype & NSys->QTDIR; +} + +om2nm(om: int): int +{ + # DMDIR == CHDIR + return om; +} + +nm2om(m: int): int +{ + # DMDIR == CHDIR + return m&~(NSys->DMAPPEND|NSys->DMEXCL|NSys->DMAUTH); +} + +oq2nq(oq: OSys->Qid): NSys->Qid +{ + q: NSys->Qid; + + isdir := oq.path&OSys->CHDIR; + q.path = big (oq.path&~OSys->CHDIR); + q.vers = oq.vers; + q.qtype = 0; + if(isdir) + q.qtype |= NSys->QTDIR; + return q; +} + +nq2oq(q: NSys->Qid): OSys->Qid +{ + oq: OSys->Qid; + + isdir := q.qtype&NSys->QTDIR; + oq.path = int q.path; + oq.vers = q.vers; + if(isdir) + oq.path |= OSys->CHDIR; + return oq; +} + +od2nd(od: OSys->Dir): NSys->Dir +{ + d: NSys->Dir; + + d.name = od.name; + d.uid = od.uid; + d.gid = od.gid; + d.muid = od.uid; + d.qid = oq2nq(od.qid); + d.mode = om2nm(od.mode); + d.atime = od.atime; + d.mtime = od.mtime; + d.length = big od.length; + d.dtype = od.dtype; + d.dev = od.dev; + return d; +} + +nd2od(d: NSys->Dir): OSys->Dir +{ + od: OSys->Dir; + + od.name = d.name; + od.uid = d.uid; + od.gid = d.gid; + od.qid = nq2oq(d.qid); + od.mode = nm2om(d.mode); + od.atime = d.atime; + od.mtime = d.mtime; + od.length = int d.length; + od.dtype = d.dtype; + od.dev = d.dev; + return od; +} + +nds2ods(ob: array of byte): array of byte +{ + i := 0; + n := 0; + ds: list of NSys->Dir; + while(i < len ob){ + (size, d) := nstyx->unpackdir(ob[i:]); + if(size == 0) + break; + ds = d :: ds; + i += size; + n++; + } + b := array[OStyx->DIRLEN * n] of byte; + for(i = (n - 1) * OStyx->DIRLEN; i >= 0; i -= OStyx->DIRLEN){ + ostyx->convD2M(b[i:], nd2od(hd ds)); + ds = tl ds; + } + return b; +} + +NTsend(fd: ref Sys->FD, ntm: ref Tmsg) +{ + if(DEBUG) + sys->fprint(sys->fildes(2), " -> %s\n", ntm.text()); + s := ntm.pack(); + sys->write(fd, s, len s); +} + +ORsend(fd: ref Sys->FD, orm: ref ORmsg) +{ + if(DEBUG) + sys->fprint(sys->fildes(2), "<- %s\n", ostyx->rmsg2s(orm)); + s := array[OStyx->MAXRPC] of byte; + n := ostyx->rmsg2d(orm, s); + if(n > 0) + sys->write(fd, s, n); +} + +readoldtmsgs(pidc: chan of int, oldclient: ref Sys->FD, oldtmsg: chan of ref OTmsg) +{ + pidc <-= sys->pctl(0, nil); + for(;;){ + oldtmsg <-= OTmsg.read(oldclient); + } +} + +readnewrmsgs(pidc: chan of int, newsrv: ref Sys->FD, newrmsg: chan of ref Rmsg) +{ + pidc <-= sys->pctl(0, nil); + for(;;){ + newrmsg <-= Rmsg.read(newsrv, Msize); + } +} + +warning(err: string) +{ + sys->fprint(sys->fildes(2), "warning: %s\n", err); +} + +fatal(err: string) +{ + sys->fprint(sys->fildes(2), "%s\n", err); + exit; +} + +nomod(mod: string, path: string) +{ + fatal(sys->sprint("can't load %s(%s): %r", mod, path)); +} + +kill(pid: int) +{ + sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill"); +} diff --git a/appl/lib/styxconv/ostyx.b b/appl/lib/styxconv/ostyx.b index ce8e0d9e..b575a0cb 100644 --- a/appl/lib/styxconv/ostyx.b +++ b/appl/lib/styxconv/ostyx.b @@ -13,43 +13,81 @@ DEBUG: con 0; CHANHASHSIZE: con 32; +init() +{ + sys = load Sys Sys->PATH; + gsofar = 0; + gdata = array[MAXRPC] of {* => byte 0}; +} + +# note that this implementation fails if we're reading OTmsgs and ORmsgs +# concurrently. luckily we don't need to in styxconv. gsofar: int; gdata: array of byte; -ORmsg.read(fd: ref Sys->FD, msize: int): ref ORmsg +ORmsg.read(fd: ref Sys->FD): ref ORmsg { - if(sys == nil) - sys = load Sys Sys->PATH; - if(gdata == nil){ - gsofar = 0; - gdata = array[msize] of byte; - } + mlen := 0; + m: ref ORmsg; for (;;){ - n := sys->read(fd, gdata[gsofar:], len gdata - gsofar); - if(n <= 0){ - m: ref ORmsg = nil; - - if(n < 0) - m = ref ORmsg.Error(-1, sys->sprint("%r")); + if(gsofar > 0) + (mlen, m) = d2rmsg(gdata[0 : gsofar]); + if(mlen == 0){ + if(gsofar == len gdata){ + ndata := array[MAXRPC] of byte; + ndata[0:] = gdata; + gdata = ndata; + } + n := sys->read(fd, gdata[gsofar:], len gdata - gsofar); + if(n <= 0) + return nil; + gsofar += n; + }else if(mlen > 0){ + if(tagof(m) == tagof(OTmsg.Write)) { + ndata := array[MAXRPC] of byte; + ndata[0:] = gdata[mlen : gsofar]; + gdata = ndata; + }else + gdata[0:] = gdata[mlen : gsofar]; + gsofar -= mlen; return m; - } - gsofar += n; - (cn, m) := d2rmsg(gdata[0: gsofar]); - if(cn == -1) + }else gsofar = 0; - else if(cn > 0){ - if(tagof(m) == tagof(ORmsg.Read)) { - ndata := array[msize] of byte; - ndata[0: ] = gdata[cn: gsofar]; + } +} + +OTmsg.read(fd: ref Sys->FD): ref OTmsg +{ + mlen := 0; + m: ref OTmsg; + for (;;){ + if(gsofar > 0) + (mlen, m) = d2tmsg(gdata[0 : gsofar]); + if(mlen == 0){ + if(gsofar == len gdata){ + ndata := array[MAXRPC] of byte; + ndata[0:] = gdata; + gdata = ndata; + } + n := sys->read(fd, gdata[gsofar:], len gdata - gsofar); + if(n <= 0) + return nil; + gsofar += n; + }else if(mlen > 0){ + if(tagof(m) == tagof(OTmsg.Write)) { + ndata := array[MAXRPC] of byte; + ndata[0:] = gdata[mlen : gsofar]; gdata = ndata; }else - gdata[0: ] = gdata[cn: gsofar]; - gsofar -= cn; + gdata[0:] = gdata[mlen : gsofar]; + gsofar -= mlen; return m; - } + }else + gsofar = 0; } } + Styxserver.new(fd: ref Sys->FD): (chan of ref OTmsg, ref Styxserver) { if (sys == nil) @@ -572,7 +610,6 @@ pstring(a: array of byte, s: string, n: int): array of byte # convert from Dir to bytes convD2M(d: array of byte, f: OSys->Dir): array of byte { - n := len d; d = pstring(d, f.name, OSys->NAMELEN); d = pstring(d, f.uid, OSys->NAMELEN); d = pstring(d, f.gid, OSys->NAMELEN); diff --git a/appl/lib/styxconv/ostyx.m b/appl/lib/styxconv/ostyx.m index de99d65a..82d94d15 100644 --- a/appl/lib/styxconv/ostyx.m +++ b/appl/lib/styxconv/ostyx.m @@ -24,6 +24,7 @@ OStyx: module devclone: fn(srv: self ref Styxserver, m: ref OTmsg.Clone): ref Chan; }; + init: fn(); d2tmsg: fn(d: array of byte): (int, ref OTmsg); d2rmsg: fn(d: array of byte): (int, ref ORmsg); tmsg2d: fn(gm: ref OTmsg, d: array of byte): int; @@ -69,6 +70,7 @@ OStyx: module fid: int; uname, aname: string; } + read: fn(fd: ref Sys->FD): ref OTmsg; }; ORmsg: adt { @@ -99,7 +101,7 @@ OStyx: module stat: OSys->Dir; } - read: fn(fd: ref Sys->FD, msize: int): ref ORmsg; + read: fn(fd: ref Sys->FD): ref ORmsg; }; MAXRPC: con 128 + OSys->ATOMICIO; |
