summaryrefslogtreecommitdiff
path: root/appl/lib/styxconv
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/styxconv
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/lib/styxconv')
-rw-r--r--appl/lib/styxconv/mkfile20
-rw-r--r--appl/lib/styxconv/ostyx.b773
-rw-r--r--appl/lib/styxconv/ostyx.m148
-rw-r--r--appl/lib/styxconv/osys.m34
-rw-r--r--appl/lib/styxconv/styxconv.b447
5 files changed, 1422 insertions, 0 deletions
diff --git a/appl/lib/styxconv/mkfile b/appl/lib/styxconv/mkfile
new file mode 100644
index 00000000..fe4ad61e
--- /dev/null
+++ b/appl/lib/styxconv/mkfile
@@ -0,0 +1,20 @@
+<../../../mkconfig
+
+TARG=\
+ ostyx.dis\
+ styxconv.dis\
+
+MODULES=\
+ ostyx.m\
+ osys.m\
+
+SYSMODULES=\
+ bufio.m\
+ draw.m\
+ styx.m\
+ styxconv.m\
+ sys.m\
+
+DISBIN=$ROOT/dis/lib/styxconv
+
+<$ROOT/mkfiles/mkdis
diff --git a/appl/lib/styxconv/ostyx.b b/appl/lib/styxconv/ostyx.b
new file mode 100644
index 00000000..ce8e0d9e
--- /dev/null
+++ b/appl/lib/styxconv/ostyx.b
@@ -0,0 +1,773 @@
+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;
+
+gsofar: int;
+gdata: array of byte;
+
+ORmsg.read(fd: ref Sys->FD, msize: int): ref ORmsg
+{
+ if(sys == nil)
+ sys = load Sys Sys->PATH;
+ if(gdata == nil){
+ gsofar = 0;
+ gdata = array[msize] of byte;
+ }
+ 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"));
+ return m;
+ }
+ gsofar += n;
+ (cn, m) := d2rmsg(gdata[0: gsofar]);
+ if(cn == -1)
+ gsofar = 0;
+ else if(cn > 0){
+ if(tagof(m) == tagof(ORmsg.Read)) {
+ ndata := array[msize] of byte;
+ ndata[0: ] = gdata[cn: gsofar];
+ gdata = ndata;
+ }else
+ gdata[0: ] = gdata[cn: gsofar];
+ gsofar -= cn;
+ return m;
+ }
+ }
+}
+
+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
+{
+ n := len d;
+ 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;
+}
diff --git a/appl/lib/styxconv/ostyx.m b/appl/lib/styxconv/ostyx.m
new file mode 100644
index 00000000..de99d65a
--- /dev/null
+++ b/appl/lib/styxconv/ostyx.m
@@ -0,0 +1,148 @@
+OStyx: module
+{
+ PATH: con "/dis/lib/styxconv/ostyx.dis";
+
+ Chan: adt {
+ fid: int;
+ qid: OSys->Qid;
+ open: int;
+ mode: int;
+ uname: string;
+ path: string;
+ data: array of byte;
+ };
+
+ Styxserver: adt {
+ fd: ref Sys->FD;
+ chans: array of list of ref Chan;
+
+ new: fn(fd: ref Sys->FD): (chan of ref OTmsg, ref Styxserver);
+ reply: fn(srv: self ref Styxserver, m: ref ORmsg): int;
+ fidtochan: fn(srv: self ref Styxserver, fid: int): ref Chan;
+ newchan: fn(srv: self ref Styxserver, fid: int): ref Chan;
+ chanfree: fn(srv: self ref Styxserver, c: ref Chan);
+ devclone: fn(srv: self ref Styxserver, m: ref OTmsg.Clone): ref Chan;
+ };
+
+ 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;
+ rmsg2d: fn(m: ref ORmsg, d: array of byte): int;
+ tmsg2s: fn(m: ref OTmsg): string; # for debugging
+ rmsg2s: fn(m: ref ORmsg): string; # for debugging
+ convD2M: fn(d: array of byte, f: OSys->Dir): array of byte;
+ convM2D: fn(d: array of byte): (array of byte, OSys->Dir);
+
+ OTmsg: adt {
+ tag: int;
+ pick {
+ Readerror =>
+ error: string; # tag is unused in this case
+ Nop =>
+ Flush =>
+ oldtag: int;
+ Clone =>
+ fid, newfid: int;
+ Walk =>
+ fid: int;
+ name: string;
+ Open =>
+ fid, mode: int;
+ Create =>
+ fid, perm, mode: int;
+ name: string;
+ Read =>
+ fid, count: int;
+ offset: big;
+ Write =>
+ fid: int;
+ offset: big;
+ data: array of byte;
+ Clunk or
+ Stat or
+ Remove =>
+ fid: int;
+ Wstat =>
+ fid: int;
+ stat: OSys->Dir;
+ Attach =>
+ fid: int;
+ uname, aname: string;
+ }
+ };
+
+ ORmsg: adt {
+ tag: int;
+ pick {
+ Nop or
+ Flush =>
+ Error =>
+ err: string;
+ Clunk or
+ Remove or
+ Clone or
+ Wstat =>
+ fid: int;
+ Walk or
+ Create or
+ Open or
+ Attach =>
+ fid: int;
+ qid: OSys->Qid;
+ Read =>
+ fid: int;
+ data: array of byte;
+ Write =>
+ fid, count: int;
+ Stat =>
+ fid: int;
+ stat: OSys->Dir;
+ }
+
+ read: fn(fd: ref Sys->FD, msize: int): ref ORmsg;
+ };
+
+ MAXRPC: con 128 + OSys->ATOMICIO;
+ DIRLEN: con 116;
+
+ Tnop, # 0
+ Rnop, # 1
+ Terror, # 2, illegal
+ Rerror, # 3
+ Tflush, # 4
+ Rflush, # 5
+ Tclone, # 6
+ Rclone, # 7
+ Twalk, # 8
+ Rwalk, # 9
+ Topen, # 10
+ Ropen, # 11
+ Tcreate, # 12
+ Rcreate, # 13
+ Tread, # 14
+ Rread, # 15
+ Twrite, # 16
+ Rwrite, # 17
+ Tclunk, # 18
+ Rclunk, # 19
+ Tremove, # 20
+ Rremove, # 21
+ Tstat, # 22
+ Rstat, # 23
+ Twstat, # 24
+ Rwstat, # 25
+ Tsession, # 26
+ Rsession, # 27
+ Tattach, # 28
+ Rattach, # 29
+ Tmax : con iota;
+
+ Einuse : con "fid already in use";
+ Ebadfid : con "bad fid";
+ Eopen : con "fid already opened";
+ Enotfound : con "file does not exist";
+ Enotdir : con "not a directory";
+ Eperm : con "permission denied";
+ Ebadarg : con "bad argument";
+ Eexists : con "file already exists";
+};
diff --git a/appl/lib/styxconv/osys.m b/appl/lib/styxconv/osys.m
new file mode 100644
index 00000000..7d04421c
--- /dev/null
+++ b/appl/lib/styxconv/osys.m
@@ -0,0 +1,34 @@
+OSys: module
+{
+ # Unique file identifier for file objects
+ Qid: adt
+ {
+ path: int;
+ vers: int;
+ };
+
+ # Return from stat and directory read
+ Dir: adt
+ {
+ name: string;
+ uid: string;
+ gid: string;
+ qid: Qid;
+ mode: int;
+ atime: int;
+ mtime: int;
+ length: int;
+ dtype: int;
+ dev: int;
+ };
+
+ # Maximum read which will be completed atomically;
+ # also the optimum block size
+ #
+ ATOMICIO: con 8192;
+
+ NAMELEN: con 28;
+ ERRLEN: con 64;
+
+ CHDIR: con int 16r80000000;
+};
diff --git a/appl/lib/styxconv/styxconv.b b/appl/lib/styxconv/styxconv.b
new file mode 100644
index 00000000..00cc18ef
--- /dev/null
+++ b/appl/lib/styxconv/styxconv.b
@@ -0,0 +1,447 @@
+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);
+ }
+}