summaryrefslogtreecommitdiff
path: root/appl/cmd/trfs.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/trfs.b')
-rw-r--r--appl/cmd/trfs.b213
1 files changed, 213 insertions, 0 deletions
diff --git a/appl/cmd/trfs.b b/appl/cmd/trfs.b
new file mode 100644
index 00000000..1ccd0639
--- /dev/null
+++ b/appl/cmd/trfs.b
@@ -0,0 +1,213 @@
+implement Trfs;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "styx.m";
+ styx: Styx;
+ Rmsg, Tmsg: import styx;
+
+Trfs: module
+{
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+Fid: adt {
+ fid: int;
+ isdir: int;
+ aux: int;
+};
+
+Table: adt[T] {
+ items: array of list of (int, T);
+ nilval: T;
+
+ new: fn(nslots: int, nilval: T): ref Table[T];
+ add: fn(t: self ref Table, id: int, x: T): int;
+ del: fn(t: self ref Table, id: int): T;
+ find: fn(t: self ref Table, id: int): T;
+};
+
+NBspace: con 16r00A0; # Unicode `no-break' space (looks like a faint box in some fonts)
+NBspacelen: con 2; # length of it in utf-8
+
+msize: int;
+lock: chan of int;
+fids: ref Table[ref Fid];
+tfids: ref Table[ref Fid];
+
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ styx = load Styx Styx->PATH;
+
+ if(len args != 3){
+ sys->fprint(sys->fildes(2), "usage: trfs dir mountpoint\n");
+ raise "fail:usage";
+ }
+ dir := hd tl args;
+ mntpt := hd tl tl args;
+ p := array[2] of ref Sys->FD;
+ q := array[2] of ref Sys->FD;
+ fids = Table[ref Fid].new(11, nil);
+ tfids = Table[ref Fid].new(11, nil);
+ lock = chan[1] of int;
+
+ styx->init();
+ sys->pipe(p);
+ sys->pipe(q);
+ if(sys->export(q[0], dir, Sys->EXPASYNC) < 0)
+ fatal("can't export " + dir);
+ spawn trfsin(p[1], q[1]);
+ spawn trfsout(p[1], q[1]);
+ if(sys->mount(p[0], nil, mntpt, Sys->MREPL|Sys->MCREATE, nil) < 0)
+ fatal("can't mount on " + mntpt);
+}
+
+trfsin(cfd, sfd: ref Sys->FD)
+{
+ while((t:=Tmsg.read(cfd, msize)) != nil){
+ pick m := t {
+ Clunk or
+ Remove =>
+ fids.del(m.fid);
+ Create =>
+ fid := ref Fid(m.fid, 0, 0);
+ fids.add(m.fid, fid);
+ addtfid(m.tag, fid);
+ m.name = tr(m.name, NBspace, ' ');
+ Open =>
+ fid := ref Fid(m.fid, 0, 0);
+ fids.add(m.fid, fid);
+ addtfid(m.tag, fid);
+ Read =>
+ fid := fids.find(m.fid);
+ addtfid(m.tag, fid);
+ if(fid.isdir){
+ m.count /= NBspacelen; # translated strings might grow by this much
+ if(m.offset == big 0)
+ fid.aux = 0;
+ m.offset -= big fid.aux;
+ }
+ Walk =>
+ for(i:=0; i<len m.names; i++)
+ m.names[i] = tr(m.names[i], NBspace, ' ');
+ Wstat =>
+ m.stat.name = tr(m.stat.name, NBspace, ' ');
+ }
+ sys->write(sfd, t.pack(), t.packedsize());
+ }
+}
+
+trfsout(cfd, sfd: ref Sys->FD)
+{
+ b := array[Styx->MAXFDATA] of byte;
+ while((r := Rmsg.read(sfd, msize)) != nil){
+ pick m := r {
+ Version =>
+ msize = m.msize;
+ if(msize > len b)
+ b = array[msize] of byte; # a bit more than needed but doesn't matter
+ Create or
+ Open =>
+ fid := deltfid(m.tag);
+ fid.isdir = m.qid.qtype & Sys->QTDIR;
+ Read =>
+ fid := deltfid(m.tag);
+ if(fid.isdir){
+ bs := 0;
+ for(n := 0; n < len m.data; ){
+ (ds, d) := styx->unpackdir(m.data[n:]);
+ if(ds <= 0)
+ break;
+ d.name = tr(d.name, ' ', NBspace);
+ b[bs:] = styx->packdir(d);
+ bs += styx->packdirsize(d);
+ n += ds;
+ }
+ fid.aux += bs-n;
+ m.data = b[0:bs];
+ }
+ Stat =>
+ m.stat.name = tr(m.stat.name, ' ', NBspace);
+ }
+ sys->write(cfd, r.pack(), r.packedsize());
+ }
+}
+
+tr(name: string, c1, c2: int): string
+{
+ for(i:=0; i<len name; i++)
+ if(name[i] == c1)
+ name[i] = c2;
+ return name;
+}
+
+Table[T].new(nslots: int, nilval: T): ref Table[T]
+{
+ if(nslots == 0)
+ nslots = 13;
+ return ref Table[T](array[nslots] of list of (int, T), nilval);
+}
+
+Table[T].add(t: self ref Table[T], id: int, x: T): int
+{
+ slot := id % len t.items;
+ for(q := t.items[slot]; q != nil; q = tl q)
+ if((hd q).t0 == id)
+ return 0;
+ t.items[slot] = (id, x) :: t.items[slot];
+ return 1;
+}
+
+Table[T].del(t: self ref Table[T], id: int): T
+{
+ p: list of (int, T);
+ slot := id % len t.items;
+ for(q := t.items[slot]; q != nil; q = tl q){
+ if((hd q).t0 == id){
+ t.items[slot] = join(p, tl q);
+ return (hd q).t1;
+ }
+ p = hd q :: p;
+ }
+ return t.nilval;
+}
+
+Table[T].find(t: self ref Table[T], id: int): T
+{
+ for(p := t.items[id % len t.items]; p != nil; p = tl p)
+ if((hd p).t0 == id)
+ return (hd p).t1;
+ return t.nilval;
+}
+
+join[T](x, y: list of (int, T)): list of (int, T)
+{
+ for(; x != nil; x = tl x)
+ y = hd x :: y;
+ return y;
+}
+
+addtfid(t: int, fid: ref Fid)
+{
+ lock <-= 1;
+ tfids.add(t, fid);
+ <- lock;
+}
+
+deltfid(t: int): ref Fid
+{
+ lock <-= 1;
+ r := tfids.del(t);
+ <- lock;
+ return r;
+}
+
+fatal(s: string)
+{
+ sys->fprint(sys->fildes(2), "trfs: %s: %r\n", s);
+ raise "fail:error";
+}