1implement Trfs; 2 3include "sys.m"; 4 sys: Sys; 5 6include "draw.m"; 7 8include "styx.m"; 9 styx: Styx; 10 Rmsg, Tmsg: import styx; 11 12Trfs: module 13{ 14 init: fn(nil: ref Draw->Context, nil: list of string); 15}; 16 17Fid: adt { 18 fid: int; 19 isdir: int; 20 aux: int; 21}; 22 23Table: adt[T] { 24 items: array of list of (int, T); 25 nilval: T; 26 27 new: fn(nslots: int, nilval: T): ref Table[T]; 28 add: fn(t: self ref Table, id: int, x: T): int; 29 del: fn(t: self ref Table, id: int): T; 30 find: fn(t: self ref Table, id: int): T; 31}; 32 33NBspace: con 16r00A0; # Unicode `no-break' space (looks like a faint box in some fonts) 34NBspacelen: con 2; # length of it in utf-8 35 36msize: int; 37lock: chan of int; 38fids: ref Table[ref Fid]; 39tfids: ref Table[ref Fid]; 40 41init(nil: ref Draw->Context, args: list of string) 42{ 43 sys = load Sys Sys->PATH; 44 styx = load Styx Styx->PATH; 45 46 if(len args != 3){ 47 sys->fprint(sys->fildes(2), "usage: trfs dir mountpoint\n"); 48 raise "fail:usage"; 49 } 50 dir := hd tl args; 51 mntpt := hd tl tl args; 52 p := array[2] of ref Sys->FD; 53 q := array[2] of ref Sys->FD; 54 fids = Table[ref Fid].new(11, nil); 55 tfids = Table[ref Fid].new(11, nil); 56 lock = chan[1] of int; 57 58 styx->init(); 59 sys->pipe(p); 60 sys->pipe(q); 61 if(sys->export(q[0], dir, Sys->EXPASYNC) < 0) 62 fatal("can't export " + dir); 63 spawn trfsin(p[1], q[1]); 64 spawn trfsout(p[1], q[1]); 65 if(sys->mount(p[0], nil, mntpt, Sys->MREPL|Sys->MCREATE, nil) < 0) 66 fatal("can't mount on " + mntpt); 67} 68 69trfsin(cfd, sfd: ref Sys->FD) 70{ 71 while((t:=Tmsg.read(cfd, msize)) != nil){ 72 pick m := t { 73 Clunk or 74 Remove => 75 fids.del(m.fid); 76 Create => 77 fid := ref Fid(m.fid, 0, 0); 78 fids.add(m.fid, fid); 79 addtfid(m.tag, fid); 80 m.name = tr(m.name, NBspace, ' '); 81 Open => 82 fid := ref Fid(m.fid, 0, 0); 83 fids.add(m.fid, fid); 84 addtfid(m.tag, fid); 85 Read => 86 fid := fids.find(m.fid); 87 addtfid(m.tag, fid); 88 if(fid.isdir){ 89 m.count /= NBspacelen; # translated strings might grow by this much 90 if(m.offset == big 0) 91 fid.aux = 0; 92 m.offset -= big fid.aux; 93 } 94 Walk => 95 for(i:=0; i<len m.names; i++) 96 m.names[i] = tr(m.names[i], NBspace, ' '); 97 Wstat => 98 m.stat.name = tr(m.stat.name, NBspace, ' '); 99 } 100 sys->write(sfd, t.pack(), t.packedsize()); 101 } 102} 103 104trfsout(cfd, sfd: ref Sys->FD) 105{ 106 b := array[Styx->MAXFDATA] of byte; 107 while((r := Rmsg.read(sfd, msize)) != nil){ 108 pick m := r { 109 Version => 110 msize = m.msize; 111 if(msize > len b) 112 b = array[msize] of byte; # a bit more than needed but doesn't matter 113 Create or 114 Open => 115 fid := deltfid(m.tag); 116 fid.isdir = m.qid.qtype & Sys->QTDIR; 117 Read => 118 fid := deltfid(m.tag); 119 if(fid.isdir){ 120 bs := 0; 121 for(n := 0; n < len m.data; ){ 122 (ds, d) := styx->unpackdir(m.data[n:]); 123 if(ds <= 0) 124 break; 125 d.name = tr(d.name, ' ', NBspace); 126 b[bs:] = styx->packdir(d); 127 bs += styx->packdirsize(d); 128 n += ds; 129 } 130 fid.aux += bs-n; 131 m.data = b[0:bs]; 132 } 133 Stat => 134 m.stat.name = tr(m.stat.name, ' ', NBspace); 135 } 136 sys->write(cfd, r.pack(), r.packedsize()); 137 } 138} 139 140tr(name: string, c1, c2: int): string 141{ 142 for(i:=0; i<len name; i++) 143 if(name[i] == c1) 144 name[i] = c2; 145 return name; 146} 147 148Table[T].new(nslots: int, nilval: T): ref Table[T] 149{ 150 if(nslots == 0) 151 nslots = 13; 152 return ref Table[T](array[nslots] of list of (int, T), nilval); 153} 154 155Table[T].add(t: self ref Table[T], id: int, x: T): int 156{ 157 slot := id % len t.items; 158 for(q := t.items[slot]; q != nil; q = tl q) 159 if((hd q).t0 == id) 160 return 0; 161 t.items[slot] = (id, x) :: t.items[slot]; 162 return 1; 163} 164 165Table[T].del(t: self ref Table[T], id: int): T 166{ 167 p: list of (int, T); 168 slot := id % len t.items; 169 for(q := t.items[slot]; q != nil; q = tl q){ 170 if((hd q).t0 == id){ 171 t.items[slot] = join(p, tl q); 172 return (hd q).t1; 173 } 174 p = hd q :: p; 175 } 176 return t.nilval; 177} 178 179Table[T].find(t: self ref Table[T], id: int): T 180{ 181 for(p := t.items[id % len t.items]; p != nil; p = tl p) 182 if((hd p).t0 == id) 183 return (hd p).t1; 184 return t.nilval; 185} 186 187join[T](x, y: list of (int, T)): list of (int, T) 188{ 189 for(; x != nil; x = tl x) 190 y = hd x :: y; 191 return y; 192} 193 194addtfid(t: int, fid: ref Fid) 195{ 196 lock <-= 1; 197 tfids.add(t, fid); 198 <- lock; 199} 200 201deltfid(t: int): ref Fid 202{ 203 lock <-= 1; 204 r := tfids.del(t); 205 <- lock; 206 return r; 207} 208 209fatal(s: string) 210{ 211 sys->fprint(sys->fildes(2), "trfs: %s: %r\n", s); 212 raise "fail:error"; 213} 214