xref: /inferno-os/appl/cmd/mntgen.b (revision 3f1f06c5d12b24c4061e5123acabf72348ff45a2)
1implement Mntgen;
2include "sys.m";
3	sys: Sys;
4include "draw.m";
5include "styx.m";
6	styx: Styx;
7	Rmsg, Tmsg: import styx;
8include "styxservers.m";
9	styxservers: Styxservers;
10	Ebadfid, Enotfound, Eopen, Einuse: import Styxservers;
11	Styxserver, readbytes, Navigator, Fid: import styxservers;
12
13	nametree: Nametree;
14	Tree: import nametree;
15
16Mntgen: module {
17	init: fn(nil: ref Draw->Context, argv: list of string);
18};
19
20Qroot: con big 16rfffffff;
21
22badmodule(p: string)
23{
24	sys->fprint(sys->fildes(2), "cannot load %s: %r\n", p);
25	raise "fail:bad module";
26}
27DEBUG: con 0;
28
29Entry: adt {
30	refcount: int;
31	path: big;
32};
33refcounts := array[10] of Entry;
34tree: ref Tree;
35nav: ref Navigator;
36
37uniq: int;
38
39init(nil: ref Draw->Context, nil: list of string)
40{
41	sys = load Sys Sys->PATH;
42	styx = load Styx Styx->PATH;
43	if (styx == nil)
44		badmodule(Styx->PATH);
45	styx->init();
46	styxservers = load Styxservers Styxservers->PATH;
47	if (styxservers == nil)
48		badmodule(Styxservers->PATH);
49	styxservers->init(styx);
50
51	nametree = load Nametree Nametree->PATH;
52	if (nametree == nil)
53		badmodule(Nametree->PATH);
54	nametree->init();
55
56	navop: chan of ref Styxservers->Navop;
57	(tree, navop) = nametree->start();
58	nav = Navigator.new(navop);
59	(tchan, srv) := Styxserver.new(sys->fildes(0), nav, Qroot);
60
61	tree.create(Qroot, dir(".", Sys->DMDIR | 8r555, Qroot));
62
63	for (;;) {
64		gm := <-tchan;
65		if (gm == nil) {
66			tree.quit();
67			exit;
68		}
69		e := handlemsg(gm, srv, tree);
70		if (e != nil)
71			srv.reply(ref Rmsg.Error(gm.tag, e));
72	}
73}
74
75walk1(c: ref Fid, name: string): string
76{
77	if (name == ".."){
78		if (c.path != Qroot)
79			decref(c.path);
80		c.walk(Sys->Qid(Qroot, 0, Sys->QTDIR));
81	} else if (c.path == Qroot) {
82		(d, nil) := nav.walk(c.path, name);
83		if (d == nil)
84			d = addentry(name);
85		else
86			incref(d.qid.path);
87		c.walk(d.qid);
88	} else
89		return Enotfound;
90	return nil;
91}
92
93handlemsg(gm: ref Styx->Tmsg, srv: ref Styxserver, nil: ref Tree): string
94{
95	pick m := gm {
96	Walk =>
97		c := srv.getfid(m.fid);
98		if(c == nil)
99			return Ebadfid;
100		if(c.isopen)
101			return Eopen;
102		if(m.newfid != m.fid){
103			nc := srv.newfid(m.newfid);
104			if(nc == nil)
105				return Einuse;
106			c = c.clone(nc);
107			incref(c.path);
108		}
109		qids := array[len m.names] of Sys->Qid;
110		oldpath := c.path;
111		oldqtype := c.qtype;
112		incref(oldpath);
113		for (i := 0; i < len m.names; i++){
114			err := walk1(c, m.names[i]);
115			if (err != nil){
116				if(m.newfid != m.fid){
117					decref(c.path);
118					srv.delfid(c);
119				}
120				c.path = oldpath;
121				c.qtype = oldqtype;
122				if(i == 0)
123					return err;
124				srv.reply(ref Rmsg.Walk(m.tag, qids[0:i]));
125				return nil;
126			}
127			qids[i] = Sys->Qid(c.path, 0, c.qtype);
128		}
129		decref(oldpath);
130		srv.reply(ref Rmsg.Walk(m.tag, qids));
131	Clunk =>
132		c := srv.clunk(m);
133		if (c != nil && c.path != Qroot)
134			decref(c.path);
135	* =>
136		srv.default(gm);
137	}
138	return nil;
139}
140
141addentry(name: string): ref Sys->Dir
142{
143	for (i := 0; i < len refcounts; i++)
144		if (refcounts[i].refcount == 0)
145			break;
146	if (i == len refcounts) {
147		refcounts = (array[len refcounts * 2] of Entry)[0:] = refcounts;
148		for (j := i; j < len refcounts; j++)
149			refcounts[j].refcount = 0;
150	}
151	d := dir(name, Sys->DMDIR|8r555, big i | (big uniq++ << 32));
152	tree.create(Qroot, d);
153	refcounts[i] = (1, d.qid.path);
154	return ref d;
155}
156
157incref(q: big)
158{
159	id := int q;
160	if (id >= 0 && id < len refcounts){
161		refcounts[id].refcount++;
162	}
163}
164
165decref(q: big)
166{
167	id := int q;
168	if (id >= 0 && id < len refcounts){
169		if (--refcounts[id].refcount == 0)
170			tree.remove(refcounts[id].path);
171	}
172}
173
174Blankdir: Sys->Dir;
175dir(name: string, perm: int, qid: big): Sys->Dir
176{
177	d := Blankdir;
178	d.name = name;
179	d.uid = "me";
180	d.gid = "me";
181	d.qid.path = qid;
182	if (perm & Sys->DMDIR)
183		d.qid.qtype = Sys->QTDIR;
184	else
185		d.qid.qtype = Sys->QTFILE;
186	d.mode = perm;
187	return d;
188}
189