diff options
Diffstat (limited to 'appl/cmd/trfs.b')
| -rw-r--r-- | appl/cmd/trfs.b | 213 |
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"; +} |
