diff options
Diffstat (limited to 'appl/lib/styxconv/old2new.b')
| -rw-r--r-- | appl/lib/styxconv/old2new.b | 480 |
1 files changed, 480 insertions, 0 deletions
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"); +} |
