diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/styxconv | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/lib/styxconv')
| -rw-r--r-- | appl/lib/styxconv/mkfile | 20 | ||||
| -rw-r--r-- | appl/lib/styxconv/ostyx.b | 773 | ||||
| -rw-r--r-- | appl/lib/styxconv/ostyx.m | 148 | ||||
| -rw-r--r-- | appl/lib/styxconv/osys.m | 34 | ||||
| -rw-r--r-- | appl/lib/styxconv/styxconv.b | 447 |
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); + } +} |
