xref: /inferno-os/appl/cmd/trfs.b (revision ad88539715c50f30c4e8fca27338158dc33feaaa)
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