ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/lib/styxconv/styxconv.b/
implement Styxconv;
include "sys.m";
sys: Sys;
include "osys.m";
include "draw.m";
include "styx.m";
styx: Styx;
Tmsg, Rmsg: import styx;
include "ostyx.m";
ostyx: OStyx;
OTmsg, ORmsg: import ostyx;
include "styxconv.m";
DEBUG: con 0;
Fid: adt
{
fid: int;
qid: OSys->Qid;
n: int;
odri: int;
dri: int;
next: cyclic ref Fid;
};
fids: ref Fid;
init()
{
sys = load Sys Sys->PATH;
if(sys == nil)
nomod("Sys", Sys->PATH);
styx = load Styx Styx->PATH;
if(styx == nil)
nomod("Styx", Styx->PATH);
ostyx = load OStyx OStyx->PATH;
if(ostyx == nil)
nomod("OStyx", OStyx->PATH);
styx->init();
}
nomod(mod: string, path: string)
{
fatal(sys->sprint("can't load %s(%s): %r", mod, path));
}
fatal(err: string)
{
sys->fprint(sys->fildes(2), "%s\n", err);
exit;
}
newfid(fid: int, qid: OSys->Qid): ref Fid
{
f := ref Fid;
f.fid = fid;
f.qid = qid;
f.n = f.odri = f.dri = 0;
f.next = fids;
fids = f;
return f;
}
clonefid(ofid: int, fid: int): ref Fid
{
if((f := findfid(ofid)) != nil)
return newfid(fid, f.qid);
return newfid(fid, (0, 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;
}
}
findfid(fid: int): ref Fid
{
for(f := fids; f != nil && f.fid != fid; f = f.next)
;
return f;
}
setfid(fid: int, qid: OSys->Qid)
{
if((f := findfid(fid)) != nil)
f.qid = qid;
}
om2nm(om: int): int
{
# DMDIR == CHDIR
return om;
}
nm2om(m: int): int
{
# DMDIR == CHDIR
return m&~(Sys->DMAPPEND|Sys->DMEXCL|Sys->DMAUTH);
}
oq2nq(oq: OSys->Qid): Sys->Qid
{
q: Sys->Qid;
isdir := oq.path&OSys->CHDIR;
q.path = big (oq.path&~OSys->CHDIR);
q.vers = oq.vers;
q.qtype = 0;
if(isdir)
q.qtype |= Sys->QTDIR;
return q;
}
nq2oq(q: Sys->Qid): OSys->Qid
{
oq: OSys->Qid;
isdir := q.qtype&Sys->QTDIR;
oq.path = int q.path;
oq.vers = q.vers;
if(isdir)
oq.path |= OSys->CHDIR;
return oq;
}
od2nd(od: OSys->Dir): Sys->Dir
{
d: Sys->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: Sys->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(fp: ref Fid, ob: array of byte): 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 := styx->packdirsize(d);
if(n+nn > fp.n) # might just happen with long file names
break;
n += nn;
}
m = i;
fp.odri += m*OStyx->DIRLEN;
fp.dri += n;
b := array[n] of byte;
n = 0;
p = ob;
for(i = 0; i < m; i++){
(p, od) = ostyx->convM2D(p);
d := od2nd(od);
q := styx->packdir(d);
nn := len q;
b[n: ] = q[0: nn];
n += nn;
}
return b;
}
Tsend(fd: ref Sys->FD, otm: ref OTmsg): int
{
if(DEBUG)
sys->print("OT: %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);
}
Rsend(fd: ref Sys->FD, rm: ref Rmsg): int
{
if(DEBUG)
sys->print("NR: %s\n", rm.text());
s := rm.pack();
if(s == nil)
return -1;
return sys->write(fd, s, len s);
}
Trecv(fd: ref Sys->FD): ref Tmsg
{
tm := Tmsg.read(fd, Styx->MAXRPC);
if(tm == nil)
exit;
if(DEBUG)
sys->print("NT: %s\n", tm.text());
return tm;
}
Rrecv(fd: ref Sys->FD): ref ORmsg
{
orm := ORmsg.read(fd, OStyx->MAXRPC);
if(orm == nil)
exit;
if(DEBUG)
sys->print("OR: %s\n", ostyx->rmsg2s(orm));
return orm;
}
clunkfid(fd2: ref Sys->FD, tm: ref Tmsg.Walk)
{
deletefid(tm.newfid);
otm := ref OTmsg.Clunk(tm.tag, tm.newfid);
Tsend(fd2, otm);
os2ns(Rrecv(fd2)); # should check return
}
# T messages: new to old (mostly)
ns2os(tm0: ref Tmsg, fd2: ref Sys->FD): (ref OTmsg, ref Rmsg)
{
otm: ref OTmsg;
rm: ref Rmsg;
i, j: int;
err: string;
otm = nil;
rm = nil;
pick tm := tm0{
Version =>
(s, v) := styx->compatible(tm, Styx->MAXRPC, nil);
rm = ref Rmsg.Version(tm.tag, s, v);
Auth =>
rm = ref Rmsg.Error(tm.tag, "authorization not required");
Attach =>
newfid(tm.fid, (0, 0));
otm = ref OTmsg.Attach(tm.tag, tm.fid, tm.uname, tm.aname);
Readerror =>
exit;
Flush =>
otm = ref OTmsg.Flush(tm.tag, tm.oldtag);
Walk =>
# multiple use of tag ok I think
n := len tm.names;
if(tm.newfid != tm.fid){
clonefid(tm.fid, tm.newfid);
if(n != 0){
otm = ref OTmsg.Clone(tm.tag, tm.fid, tm.newfid);
Tsend(fd2, otm);
os2ns(Rrecv(fd2)); # should check return
}
}
qids := array[n] of Sys->Qid;
if(n == 0)
otm = ref OTmsg.Clone(tm.tag, tm.fid, tm.newfid);
else if(n == 1){
otm = ref OTmsg.Walk(tm.tag, tm.newfid, tm.names[0]);
Tsend(fd2, otm);
rm = os2ns(Rrecv(fd2));
pick rm0 := rm{
Readerror =>
exit;
Error =>
if(tm.newfid != tm.fid)
clunkfid(fd2, tm);
Walk =>
* =>
fatal("bad Rwalk message");
}
otm = nil;
}
else{
loop:
for(i = 0; i < n; i++){
otm = ref OTmsg.Walk(tm.tag, tm.newfid, tm.names[i]);
Tsend(fd2, otm);
rm = os2ns(Rrecv(fd2));
pick rm0 := rm{
Readerror =>
exit;
Error =>
err = rm0.ename;
break loop;
Walk =>
qids[i] = rm0.qids[0];
* =>
fatal("bad Rwalk message");
}
}
if(i != n && i != 0 && tm.fid == tm.newfid){
for(j = 0; j < i; j++){
otm = ref OTmsg.Walk(tm.tag, tm.fid, "..");
Tsend(fd2, otm);
rm = os2ns(Rrecv(fd2));
pick rm0 := rm{
Readerror =>
exit;
Walk =>
* =>
fatal("cannot retrieve fid");
}
}
}
if(i != n && tm.newfid != tm.fid)
clunkfid(fd2, tm);
otm = nil;
if(i == 0)
rm = ref Rmsg.Error(tm.tag, err);
else
rm = ref Rmsg.Walk(tm.tag, qids[0: i]);
}
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.qid.path&OSys->CHDIR){
fp.n = count;
count = (count/OStyx->DIRLEN)*OStyx->DIRLEN;
if(int offset != fp.dri)
fatal("unexpected offset in Read");
offset = big fp.odri;
}
otm = ref OTmsg.Read(tm.tag, tm.fid, count, offset);
Write =>
otm = ref OTmsg.Write(tm.tag, tm.fid, tm.offset, tm.data);
Clunk =>
deletefid(tm.fid);
otm = ref OTmsg.Clunk(tm.tag, tm.fid);
Remove =>
deletefid(tm.fid);
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");
}
if(otm == nil && rm == nil || otm != nil && rm != nil)
fatal("both nil or not in ns2os");
return (otm, rm);
}
# R messages: old to new
os2ns(orm0: ref ORmsg): ref Rmsg
{
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 =>
setfid(orm.fid, orm.qid);
rm = ref Rmsg.Walk(orm.tag, array[1] of { * => oq2nq(orm.qid) });
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.qid.path&OSys->CHDIR)
data = ods2nds(fp, data);
rm = ref Rmsg.Read(orm.tag, data);
Write =>
rm = ref Rmsg.Write(orm.tag, orm.count);
Clunk =>
rm = ref Rmsg.Clunk(orm.tag);
Remove =>
rm = ref Rmsg.Remove(orm.tag);
Stat =>
rm = ref Rmsg.Stat(orm.tag, od2nd(orm.stat));
Wstat =>
rm = ref Rmsg.Wstat(orm.tag);
Attach =>
setfid(orm.fid, orm.qid);
rm = ref Rmsg.Attach(orm.tag, oq2nq(orm.qid));
* =>
fatal("bad R message");
}
if(rm == nil)
fatal("nil in os2ns");
return rm;
}
styxconv(fd1: ref Sys->FD, fd2: ref Sys->FD, c: chan of int)
{
c <-= sys->pctl(0, nil);
for(;;){
tm := Trecv(fd1);
(otm, rm) := ns2os(tm, fd2);
if(otm != nil){
Tsend(fd2, otm);
orm := Rrecv(fd2);
rm = os2ns(orm);
}
Rsend(fd1, rm);
}
}