| @@ -0,0 +1,213 @@ |
| | 1 | implement Trfs; |
| | 2 | |
| | 3 | include "sys.m"; |
| | 4 | sys: Sys; |
| | 5 | |
| | 6 | include "draw.m"; |
| | 7 | |
| | 8 | include "styx.m"; |
| | 9 | styx: Styx; |
| | 10 | Rmsg, Tmsg: import styx; |
| | 11 | |
| | 12 | Trfs: module |
| | 13 | { |
| | 14 | init: fn(nil: ref Draw->Context, nil: list of string); |
| | 15 | }; |
| | 16 | |
| | 17 | Fid: adt { |
| | 18 | fid: int; |
| | 19 | isdir: int; |
| | 20 | aux: int; |
| | 21 | }; |
| | 22 | |
| | 23 | Table: 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 | |
| | 33 | NBspace: con 16r00A0; # Unicode `no-break' space (looks like a faint box in some fonts) |
| | 34 | NBspacelen: con 2; # length of it in utf-8 |
| | 35 | |
| | 36 | msize: int; |
| | 37 | lock: chan of int; |
| | 38 | fids: ref Table[ref Fid]; |
| | 39 | tfids: ref Table[ref Fid]; |
| | 40 | |
| | 41 | init(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 | |
| | 69 | trfsin(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 | |
| | 104 | trfsout(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 | |
| | 140 | tr(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 | |
| | 148 | Table[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 | |
| | 155 | Table[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 | |
| | 165 | Table[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 | |
| | 179 | Table[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 | |
| | 187 | join[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 | |
| | 194 | addtfid(t: int, fid: ref Fid) |
| | 195 | { |
| | 196 | lock <-= 1; |
| | 197 | tfids.add(t, fid); |
| | 198 | <- lock; |
| | 199 | } |
| | 200 | |
| | 201 | deltfid(t: int): ref Fid |
| | 202 | { |
| | 203 | lock <-= 1; |
| | 204 | r := tfids.del(t); |
| | 205 | <- lock; |
| | 206 | return r; |
| | 207 | } |
| | 208 | |
| | 209 | fatal(s: string) |
| | 210 | { |
| | 211 | sys->fprint(sys->fildes(2), "trfs: %s: %r\n", s); |
| | 212 | raise "fail:error"; |
| | 213 | } |