ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/lib/styxconv/ostyx.b/
implement OStyx;
#
# Copyright © 1999 Vita Nuova Limited. All rights reserved.
#
include "sys.m";
sys: Sys;
include "osys.m";
include "ostyx.m";
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): ref ORmsg
{
mlen := 0;
m: ref ORmsg;
for (;;){
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;
}else
gsofar = 0;
}
}
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[mlen : gsofar];
gsofar -= mlen;
return m;
}else
gsofar = 0;
}
}
Styxserver.new(fd: ref Sys->FD): (chan of ref OTmsg, ref Styxserver)
{
if (sys == nil)
sys = load Sys Sys->PATH;
tchan := chan of ref OTmsg;
srv := ref Styxserver(fd, array[CHANHASHSIZE] of list of ref Chan);
sync := chan of int;
spawn tmsgreader(fd, tchan, sync);
<-sync;
return (tchan, srv);
}
tmsgreader(fd: ref Sys->FD, tchan: chan of ref OTmsg, sync: chan of int)
{
sys->pctl(Sys->NEWFD|Sys->NEWNS, fd.fd :: nil);
sync <-= 1;
fd = sys->fildes(fd.fd);
data := array[MAXRPC] of byte;
sofar := 0;
for (;;) {
n := sys->read(fd, data[sofar:], len data - sofar);
if (n <= 0) {
m: ref OTmsg = nil;
if (n < 0)
m = ref OTmsg.Readerror(-1, sys->sprint("%r"));
tchan <-= m;
return;
}
sofar += n;
(cn, m) := d2tmsg(data[0:sofar]);
if (cn == -1) {
# on msg format error, flush any data and
# hope it'll be alright in the future.
sofar = 0;
} else if (cn > 0) {
# if it's a write message, then the buffer is used in
# the message, so allocate another one to avoid
# aliasing.
if (tagof(m) == tagof(OTmsg.Write)) {
ndata := array[MAXRPC] of byte;
ndata[0:] = data[cn:sofar];
data = ndata;
} else
data[0:] = data[cn:sofar];
sofar -= cn;
tchan <-= m;
m = nil;
}
}
}
Styxserver.reply(srv: self ref Styxserver, m: ref ORmsg): int
{
d := array[MAXRPC] of byte;
if (DEBUG)
sys->fprint(sys->fildes(2), "%s\n", rmsg2s(m));
n := rmsg2d(m, d);
return sys->write(srv.fd, d, n);
}
type2tag := array[] of {
Tnop => tagof(OTmsg.Nop),
Tflush => tagof(OTmsg.Flush),
Tclone => tagof(OTmsg.Clone),
Twalk => tagof(OTmsg.Walk),
Topen => tagof(OTmsg.Open),
Tcreate => tagof(OTmsg.Create),
Tread => tagof(OTmsg.Read),
Twrite => tagof(OTmsg.Write),
Tclunk => tagof(OTmsg.Clunk),
Tremove => tagof(OTmsg.Remove),
Tstat => tagof(OTmsg.Stat),
Twstat => tagof(OTmsg.Wstat),
Tattach => tagof(OTmsg.Attach),
* => -1
};
msglen := array[] of {
Tnop => 3,
Tflush => 5,
Tclone => 7,
Twalk => 33,
Topen => 6,
Tcreate => 38,
Tread => 15,
Twrite => 16, # header only; excludes data
Tclunk => 5,
Tremove => 5,
Tstat => 5,
Twstat => 121,
Tattach => 5+2*OSys->NAMELEN,
Rnop => -3,
Rerror => -67,
Rflush => -3,
Rclone => -5,
Rwalk => -13,
Ropen => -13,
Rcreate => -13,
Rread => -8, # header only; excludes data
Rwrite => -7,
Rclunk => -5,
Rremove => -5,
Rstat => -121,
Rwstat => -5,
Rsession => -0,
Rattach => -13,
* => 0
};
d2tmsg(d: array of byte): (int, ref OTmsg)
{
tag: int;
gmsg: ref OTmsg;
n := len d;
if (n < 3)
return (0, nil);
t: int;
(d, t) = gchar(d);
if (t < 0 || t >= len msglen || msglen[t] <= 0)
return (-1, nil);
if (n < msglen[t])
return (0, nil);
(d, tag) = gshort(d);
case t {
Tnop =>
msg := ref OTmsg.Nop;
gmsg = msg;
Tflush =>
msg := ref OTmsg.Flush;
(d, msg.oldtag) = gshort(d);
gmsg = msg;
Tclone =>
msg := ref OTmsg.Clone;
(d, msg.fid) = gshort(d);
(d, msg.newfid) = gshort(d);
gmsg = msg;
Twalk =>
msg := ref OTmsg.Walk;
(d, msg.fid) = gshort(d);
(d, msg.name) = gstring(d, OSys->NAMELEN);
gmsg = msg;
Topen =>
msg := ref OTmsg.Open;
(d, msg.fid) = gshort(d);
(d, msg.mode) = gchar(d);
gmsg = msg;
Tcreate =>
msg := ref OTmsg.Create;
(d, msg.fid) = gshort(d);
(d, msg.name) = gstring(d, OSys->NAMELEN);
(d, msg.perm) = glong(d);
(d, msg.mode) = gchar(d);
gmsg = msg;
Tread =>
msg := ref OTmsg.Read;
(d, msg.fid) = gshort(d);
(d, msg.offset) = gbig(d);
if (msg.offset < big 0)
msg.offset = big 0;
(d, msg.count) = gshort(d);
gmsg = msg;
Twrite =>
count: int;
msg := ref OTmsg.Write;
(d, msg.fid) = gshort(d);
(d, msg.offset) = gbig(d);
if (msg.offset < big 0)
msg.offset = big 0;
(d, count) = gshort(d);
if (count > Sys->ATOMICIO)
return (-1, nil);
if (len d < 1 + count)
return (0, nil);
d = d[1:];
msg.data = d[0:count];
d = d[count:];
gmsg = msg;
Tclunk =>
msg := ref OTmsg.Clunk;
(d, msg.fid) = gshort(d);
gmsg = msg;
Tremove =>
msg := ref OTmsg.Remove;
(d, msg.fid) = gshort(d);
gmsg = msg;
Tstat =>
msg := ref OTmsg.Stat;
(d, msg.fid) = gshort(d);
gmsg = msg;
Twstat =>
msg := ref OTmsg.Wstat;
(d, msg.fid) = gshort(d);
(d, msg.stat) = convM2D(d);
gmsg = msg;
Tattach =>
msg := ref OTmsg.Attach;
(d, msg.fid) = gshort(d);
(d, msg.uname) = gstring(d, OSys->NAMELEN);
(d, msg.aname) = gstring(d, OSys->NAMELEN);
gmsg = msg;
* =>
return (-1, nil);
}
gmsg.tag = tag;
return (n - len d, gmsg);
}
d2rmsg(d: array of byte): (int, ref ORmsg)
{
tag: int;
gmsg: ref ORmsg;
n := len d;
if (n < 3)
return (0, nil);
t: int;
(d, t) = gchar(d);
if (t < 0 || t >= len msglen || msglen[t] >= 0)
return (-1, nil);
if (n < -msglen[t])
return (0, nil);
(d, tag) = gshort(d);
case t {
Rerror =>
msg := ref ORmsg.Error;
(d, msg.err) = gstring(d, OSys->ERRLEN);
gmsg = msg;
Rnop =>
msg := ref ORmsg.Nop;
gmsg = msg;
Rflush =>
msg := ref ORmsg.Flush;
gmsg = msg;
Rclone =>
msg := ref ORmsg.Clone;
(d, msg.fid) = gshort(d);
gmsg = msg;
Rwalk =>
msg := ref ORmsg.Walk;
(d, msg.fid) = gshort(d);
(d, msg.qid.path) = glong(d);
(d, msg.qid.vers) = glong(d);
gmsg = msg;
Ropen =>
msg := ref ORmsg.Open;
(d, msg.fid) = gshort(d);
(d, msg.qid.path) = glong(d);
(d, msg.qid.vers) = glong(d);
gmsg = msg;
Rcreate =>
msg := ref ORmsg.Create;
(d, msg.fid) = gshort(d);
(d, msg.qid.path) = glong(d);
(d, msg.qid.vers) = glong(d);
gmsg = msg;
Rread =>
count: int;
msg := ref ORmsg.Read;
(d, msg.fid) = gshort(d);
(d, count) = gshort(d);
if (count > Sys->ATOMICIO)
return (-1, nil);
if (len d < 1 + count)
return (0, nil);
d = d[1:];
msg.data = d[0:count];
d = d[count:];
gmsg = msg;
Rwrite =>
msg := ref ORmsg.Write;
(d, msg.fid) = gshort(d);
(d, msg.count) = gshort(d);
gmsg = msg;
Rclunk =>
msg := ref ORmsg.Clunk;
(d, msg.fid) = gshort(d);
gmsg = msg;
Rremove =>
msg := ref ORmsg.Remove;
(d, msg.fid) = gshort(d);
gmsg = msg;
Rstat =>
msg := ref ORmsg.Stat;
(d, msg.fid) = gshort(d);
(d, msg.stat) = convM2D(d);
gmsg = msg;
Rwstat =>
msg := ref ORmsg.Wstat;
(d, msg.fid) = gshort(d);
gmsg = msg;
Rattach =>
msg := ref ORmsg.Attach;
(d, msg.fid) = gshort(d);
(d, msg.qid.path) = glong(d);
(d, msg.qid.vers) = glong(d);
gmsg = msg;
* =>
return (-1, nil);
}
gmsg.tag = tag;
return (n - len d, gmsg);
}
ttag2type := array[] of {
tagof(OTmsg.Readerror) => Terror,
tagof(OTmsg.Nop) => Tnop,
tagof(OTmsg.Flush) => Tflush,
tagof(OTmsg.Clone) => Tclone,
tagof(OTmsg.Walk) => Twalk,
tagof(OTmsg.Open) => Topen,
tagof(OTmsg.Create) => Tcreate,
tagof(OTmsg.Read) => Tread,
tagof(OTmsg.Write) => Twrite,
tagof(OTmsg.Clunk) => Tclunk,
tagof(OTmsg.Stat) => Tstat,
tagof(OTmsg.Remove) => Tremove,
tagof(OTmsg.Wstat) => Twstat,
tagof(OTmsg.Attach) => Tattach,
};
tag2type := array[] of {
tagof ORmsg.Nop => Rnop,
tagof ORmsg.Flush => Rflush,
tagof ORmsg.Error => Rerror,
tagof ORmsg.Clone => Rclone,
tagof ORmsg.Walk => Rwalk,
tagof ORmsg.Open => Ropen,
tagof ORmsg.Create => Rcreate,
tagof ORmsg.Read => Rread,
tagof ORmsg.Write => Rwrite,
tagof ORmsg.Clunk => Rclunk,
tagof ORmsg.Remove => Rremove,
tagof ORmsg.Stat => Rstat,
tagof ORmsg.Wstat => Rwstat,
tagof ORmsg.Attach => Rattach,
};
tmsg2d(gm: ref OTmsg, d: array of byte): int
{
n := len d;
d = pchar(d, ttag2type[tagof gm]);
d = pshort(d, gm.tag);
pick m := gm {
Nop =>
Flush =>
d = pshort(d, m.oldtag);
Clone =>
d = pshort(d, m.fid);
d = pshort(d, m.newfid);
Walk =>
d = pshort(d, m.fid);
d = pstring(d, m.name, OSys->NAMELEN);
Open =>
d = pshort(d, m.fid);
d = pchar(d, m.mode);
Create =>
d = pshort(d, m.fid);
d = pstring(d, m.name, OSys->NAMELEN);
d = plong(d, m.perm);
d = pchar(d, m.mode);
Read =>
d = pshort(d, m.fid);
d = pbig(d, m.offset);
d = pshort(d, m.count);
Write =>
data := m.data;
if (len data > Sys->ATOMICIO)
data = data[0:Sys->ATOMICIO];
d = pshort(d, m.fid);
d = pbig(d, m.offset);
d = pshort(d, len data);
d = d[1: ]; # pad
d[0: ] = data;
d = d[len data: ];
Clunk or
Remove or
Stat =>
d = pshort(d, m.fid);
Wstat =>
d = pshort(d, m.fid);
d = convD2M(d, m.stat);
Attach =>
d = pshort(d, m.fid);
d = pstring(d, m.uname, OSys->NAMELEN);
d = pstring(d, m.aname, OSys->NAMELEN);
}
return n - len d;
}
rmsg2d(gm: ref ORmsg, d: array of byte): int
{
n := len d;
d = pchar(d, tag2type[tagof gm]);
d = pshort(d, gm.tag);
pick m := gm {
Nop or
Flush =>
Error =>
d = pstring(d, m.err, OSys->ERRLEN);
Clunk or
Remove or
Clone or
Wstat =>
d = pshort(d, m.fid);
Walk or
Create or
Open or
Attach =>
d = pshort(d, m.fid);
d = plong(d, m.qid.path);
d = plong(d, m.qid.vers);
Read =>
d = pshort(d, m.fid);
data := m.data;
if (len data > Sys->ATOMICIO)
data = data[0:Sys->ATOMICIO];
d = pshort(d, len data);
d = d[1:]; # pad
d[0:] = data;
d = d[len data:];
Write =>
d = pshort(d, m.fid);
d = pshort(d, m.count);
Stat =>
d = pshort(d, m.fid);
d = convD2M(d, m.stat);
}
return n - len d;
}
gchar(a: array of byte): (array of byte, int)
{
return (a[1:], int a[0]);
}
gshort(a: array of byte): (array of byte, int)
{
return (a[2:], int a[1]<<8 | int a[0]);
}
glong(a: array of byte): (array of byte, int)
{
return (a[4:], int a[0] | int a[1]<<8 | int a[2]<<16 | int a[3]<<24);
}
gbig(a: array of byte): (array of byte, big)
{
return (a[8:],
big a[0] | big a[1] << 8 |
big a[2] << 16 | big a[3] << 24 |
big a[4] << 32 | big a[5] << 40 |
big a[6] << 48 | big a[7] << 56);
}
gstring(a: array of byte, n: int): (array of byte, string)
{
i: int;
for (i = 0; i < n; i++)
if (a[i] == byte 0)
break;
return (a[n:], string a[0:i]);
}
pchar(a: array of byte, v: int): array of byte
{
a[0] = byte v;
return a[1:];
}
pshort(a: array of byte, v: int): array of byte
{
a[0] = byte v;
a[1] = byte (v >> 8);
return a[2:];
}
plong(a: array of byte, v: int): array of byte
{
a[0] = byte v;
a[1] = byte (v >> 8);
a[2] = byte (v >> 16);
a[3] = byte (v >> 24);
return a[4:];
}
pbig(a: array of byte, v: big): array of byte
{
a[0] = byte v;
a[1] = byte (v >> 8);
a[2] = byte (v >> 16);
a[3] = byte (v >> 24);
a[4] = byte (v >> 32);
a[5] = byte (v >> 40);
a[6] = byte (v >> 58);
a[7] = byte (v >> 56);
return a[8:];
}
pstring(a: array of byte, s: string, n: int): array of byte
{
sd := array of byte s;
if (len sd > n - 1)
sd = sd[0:n-1];
a[0:] = sd;
for (i := len sd; i < n; i++)
a[i] = byte 0;
return a[n:];
}
# convert from Dir to bytes
convD2M(d: array of byte, f: OSys->Dir): array of byte
{
d = pstring(d, f.name, OSys->NAMELEN);
d = pstring(d, f.uid, OSys->NAMELEN);
d = pstring(d, f.gid, OSys->NAMELEN);
d = plong(d, f.qid.path);
d = plong(d, f.qid.vers);
d = plong(d, f.mode);
d = plong(d, f.atime);
d = plong(d, f.mtime);
d = pbig(d, big f.length); # the length field in OSys->Dir should really be big.
d = pshort(d, f.dtype);
d = pshort(d, f.dev);
return d;
}
# convert from bytes to Dir
convM2D(d: array of byte): (array of byte, OSys->Dir)
{
f: OSys->Dir;
(d, f.name) = gstring(d, OSys->NAMELEN);
(d, f.uid) = gstring(d, OSys->NAMELEN);
(d, f.gid) = gstring(d, OSys->NAMELEN);
(d, f.qid.path) = glong(d);
(d, f.qid.vers) = glong(d);
(d, f.mode) = glong(d);
(d, f.atime) = glong(d);
(d, f.mtime) = glong(d);
length: big;
(d, length) = gbig(d);
f.length = int length;
(d, f.dtype) = gshort(d);
(d, f.dev) = gshort(d);
return (d, f);
}
tmsgtags := array[] of {
tagof(OTmsg.Readerror) => "Readerror",
tagof(OTmsg.Nop) => "Nop",
tagof(OTmsg.Flush) => "Flush",
tagof(OTmsg.Clone) => "Clone",
tagof(OTmsg.Walk) => "Walk",
tagof(OTmsg.Open) => "Open",
tagof(OTmsg.Create) => "Create",
tagof(OTmsg.Read) => "Read",
tagof(OTmsg.Write) => "Write",
tagof(OTmsg.Clunk) => "Clunk",
tagof(OTmsg.Stat) => "Stat",
tagof(OTmsg.Remove) => "Remove",
tagof(OTmsg.Wstat) => "Wstat",
tagof(OTmsg.Attach) => "Attach",
};
rmsgtags := array[] of {
tagof(ORmsg.Nop) => "Nop",
tagof(ORmsg.Flush) => "Flush",
tagof(ORmsg.Error) => "Error",
tagof(ORmsg.Clunk) => "Clunk",
tagof(ORmsg.Remove) => "Remove",
tagof(ORmsg.Clone) => "Clone",
tagof(ORmsg.Wstat) => "Wstat",
tagof(ORmsg.Walk) => "Walk",
tagof(ORmsg.Create) => "Create",
tagof(ORmsg.Open) => "Open",
tagof(ORmsg.Attach) => "Attach",
tagof(ORmsg.Read) => "Read",
tagof(ORmsg.Write) => "Write",
tagof(ORmsg.Stat) => "Stat",
};
tmsg2s(gm: ref OTmsg): string
{
if (gm == nil)
return "OTmsg.nil";
s := "OTmsg."+tmsgtags[tagof(gm)]+"("+string gm.tag;
pick m:= gm {
Readerror =>
s += ", \""+m.error+"\"";
Nop =>
Flush =>
s += ", " + string m.oldtag;
Clone =>
s += ", " + string m.fid + ", " + string m.newfid;
Walk =>
s += ", " + string m.fid + ", \""+m.name+"\"";
Open =>
s += ", " + string m.fid + ", " + string m.mode;
Create =>
s += ", " + string m.fid + ", " + string m.perm + ", "
+ string m.mode + ", \""+m.name+"\"";
Read =>
s += ", " + string m.fid + ", " + string m.count + ", " + string m.offset;
Write =>
s += ", " + string m.fid + ", " + string m.offset
+ ", data["+string len m.data+"]";
Clunk or
Stat or
Remove =>
s += ", " + string m.fid;
Wstat =>
s += ", " + string m.fid;
Attach =>
s += ", " + string m.fid + ", \""+m.uname+"\", \"" + m.aname + "\"";
}
return s + ")";
}
rmsg2s(gm: ref ORmsg): string
{
if (sys == nil)
sys = load Sys Sys->PATH;
if (gm == nil)
return "ORmsg.nil";
s := "ORmsg."+rmsgtags[tagof(gm)]+"("+string gm.tag;
pick m := gm {
Nop or
Flush =>
Error =>
s +=", \""+m.err+"\"";
Clunk or
Remove or
Clone or
Wstat =>
s += ", " + string m.fid;
Walk or
Create or
Open or
Attach =>
s += ", " + string m.fid + sys->sprint(", %ux.%d", m.qid.path, m.qid.vers);
Read =>
s += ", " + string m.fid + ", data["+string len m.data+"]";
Write =>
s += ", " + string m.fid + ", " + string m.count;
Stat =>
s += ", " + string m.fid;
}
return s + ")";
}
Styxserver.fidtochan(srv: self ref Styxserver, fid: int): ref Chan
{
for (l := srv.chans[fid & (CHANHASHSIZE-1)]; l != nil; l = tl l)
if ((hd l).fid == fid)
return hd l;
return nil;
}
Styxserver.newchan(srv: self ref Styxserver, fid: int): ref Chan
{
# fid already in use
if ((c := srv.fidtochan(fid)) != nil)
return nil;
c = ref Chan;
c.qid = OSys->Qid(0, 0);
c.open = 0;
c.mode = 0;
c.fid = fid;
slot := fid & (CHANHASHSIZE-1);
srv.chans[slot] = c :: srv.chans[slot];
return c;
}
Styxserver.chanfree(srv: self ref Styxserver, c: ref Chan)
{
slot := c.fid & (CHANHASHSIZE-1);
nl: list of ref Chan;
for (l := srv.chans[slot]; l != nil; l = tl l)
if ((hd l).fid != c.fid)
nl = (hd l) :: nl;
srv.chans[slot] = nl;
}
Styxserver.devclone(srv: self ref Styxserver, m: ref OTmsg.Clone): ref Chan
{
oc := srv.fidtochan(m.fid);
if (oc == nil) {
srv.reply(ref ORmsg.Error(m.tag, Ebadfid));
return nil;
}
if (oc.open) {
srv.reply(ref ORmsg.Error(m.tag, Eopen));
return nil;
}
c := srv.newchan(m.newfid);
if (c == nil) {
srv.reply(ref ORmsg.Error(m.tag, Einuse));
return nil;
}
c.qid = oc.qid;
c.uname = oc.uname;
c.open = oc.open;
c.mode = oc.mode;
c.path = oc.path;
c.data = oc.data;
srv.reply(ref ORmsg.Clone(m.tag, m.fid));
return c;
}