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