xref: /inferno-os/appl/lib/styxlib.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Styxlib;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsyth#
4*37da2899SCharles.Forsyth# Copyright © 1999 Vita Nuova Limited.  All rights reserved.
5*37da2899SCharles.Forsyth# Revisions copyright © 2002 Vita Nuova Holdings Limited.  All rights reserved.
6*37da2899SCharles.Forsyth#
7*37da2899SCharles.Forsyth
8*37da2899SCharles.Forsythinclude "sys.m";
9*37da2899SCharles.Forsyth	sys: Sys;
10*37da2899SCharles.Forsythinclude "styx.m";
11*37da2899SCharles.Forsyth	styx: Styx;
12*37da2899SCharles.Forsyth	Tmsg, Rmsg: import styx;
13*37da2899SCharles.Forsyth
14*37da2899SCharles.Forsythinclude "styxlib.m";
15*37da2899SCharles.Forsyth
16*37da2899SCharles.ForsythCHANHASHSIZE: con 32;
17*37da2899SCharles.Forsythstarttime: int;
18*37da2899SCharles.Forsythtimefd: ref Sys->FD;
19*37da2899SCharles.Forsyth
20*37da2899SCharles.ForsythDEBUG: con 0;
21*37da2899SCharles.Forsyth
22*37da2899SCharles.Forsythinit(s: Styx): string
23*37da2899SCharles.Forsyth{
24*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
25*37da2899SCharles.Forsyth	styx = s;	# our caller inits
26*37da2899SCharles.Forsyth	return nil;
27*37da2899SCharles.Forsyth}
28*37da2899SCharles.Forsyth
29*37da2899SCharles.ForsythStyxserver.new(fd: ref Sys->FD): (chan of ref Tmsg, ref Styxserver)
30*37da2899SCharles.Forsyth{
31*37da2899SCharles.Forsyth	starttime = now();
32*37da2899SCharles.Forsyth	srv := ref Styxserver(fd, array[CHANHASHSIZE] of list of ref Chan, getuname(), 0);
33*37da2899SCharles.Forsyth	if(fd == nil)
34*37da2899SCharles.Forsyth		return (nil, srv);
35*37da2899SCharles.Forsyth	tchan := chan of ref Tmsg;
36*37da2899SCharles.Forsyth	sync := chan of int;
37*37da2899SCharles.Forsyth	spawn tmsgreader(fd, srv, tchan, sync);
38*37da2899SCharles.Forsyth	<-sync;
39*37da2899SCharles.Forsyth	return (tchan, srv);
40*37da2899SCharles.Forsyth}
41*37da2899SCharles.Forsyth
42*37da2899SCharles.Forsythnow(): int
43*37da2899SCharles.Forsyth{
44*37da2899SCharles.Forsyth	if(timefd == nil){
45*37da2899SCharles.Forsyth		timefd = sys->open("/dev/time", sys->OREAD);
46*37da2899SCharles.Forsyth		if(timefd == nil)
47*37da2899SCharles.Forsyth			return 0;
48*37da2899SCharles.Forsyth	}
49*37da2899SCharles.Forsyth	buf := array[64] of byte;
50*37da2899SCharles.Forsyth	sys->seek(timefd, big 0, 0);
51*37da2899SCharles.Forsyth	n := sys->read(timefd, buf, len buf);
52*37da2899SCharles.Forsyth	if(n < 0)
53*37da2899SCharles.Forsyth		return 0;
54*37da2899SCharles.Forsyth
55*37da2899SCharles.Forsyth	t := (big string buf[0:n]) / big 1000000;
56*37da2899SCharles.Forsyth	return int t;
57*37da2899SCharles.Forsyth}
58*37da2899SCharles.Forsyth
59*37da2899SCharles.Forsyth
60*37da2899SCharles.Forsythgetuname(): string
61*37da2899SCharles.Forsyth{
62*37da2899SCharles.Forsyth	if ((fd := sys->open("/dev/user", Sys->OREAD)) == nil)
63*37da2899SCharles.Forsyth		return "unknown";
64*37da2899SCharles.Forsyth	buf := array[Sys->NAMEMAX] of byte;
65*37da2899SCharles.Forsyth	n := sys->read(fd, buf, len buf);
66*37da2899SCharles.Forsyth	if (n <= 0)
67*37da2899SCharles.Forsyth		return "unknown";
68*37da2899SCharles.Forsyth	return string buf[0:n];
69*37da2899SCharles.Forsyth}
70*37da2899SCharles.Forsyth
71*37da2899SCharles.Forsythtmsgreader(fd: ref Sys->FD, srv: ref Styxserver, tchan: chan of ref Tmsg, sync: chan of int)
72*37da2899SCharles.Forsyth{
73*37da2899SCharles.Forsyth	sys->pctl(Sys->NEWFD|Sys->NEWNS, fd.fd :: nil);
74*37da2899SCharles.Forsyth	sync <-= 1;
75*37da2899SCharles.Forsyth	fd = sys->fildes(fd.fd);
76*37da2899SCharles.Forsyth	while((m := Tmsg.read(fd, srv.msize)) != nil && tagof m != tagof Tmsg.Readerror){
77*37da2899SCharles.Forsyth		tchan <-= m;
78*37da2899SCharles.Forsyth		m = nil;
79*37da2899SCharles.Forsyth	}
80*37da2899SCharles.Forsyth	tchan <-= m;
81*37da2899SCharles.Forsyth}
82*37da2899SCharles.Forsyth
83*37da2899SCharles.ForsythStyxserver.reply(srv: self ref Styxserver, m: ref Rmsg): int
84*37da2899SCharles.Forsyth{
85*37da2899SCharles.Forsyth	if (DEBUG)
86*37da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "%s\n", m.text());
87*37da2899SCharles.Forsyth	a := m.pack();
88*37da2899SCharles.Forsyth	if(a == nil)
89*37da2899SCharles.Forsyth		return -1;
90*37da2899SCharles.Forsyth	return sys->write(srv.fd, a, len a);
91*37da2899SCharles.Forsyth}
92*37da2899SCharles.Forsyth
93*37da2899SCharles.ForsythStyxserver.devversion(srv: self ref Styxserver, m: ref Tmsg.Version): int
94*37da2899SCharles.Forsyth{
95*37da2899SCharles.Forsyth	if(srv.msize <= 0)
96*37da2899SCharles.Forsyth		srv.msize = Styx->MAXRPC;
97*37da2899SCharles.Forsyth	(msize, version) := styx->compatible(m, srv.msize, Styx->VERSION);
98*37da2899SCharles.Forsyth	if(msize < 128){
99*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, "unusable message size"));
100*37da2899SCharles.Forsyth		return -1;
101*37da2899SCharles.Forsyth	}
102*37da2899SCharles.Forsyth	srv.msize = msize;
103*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Version(m.tag, msize, version));
104*37da2899SCharles.Forsyth	return 0;
105*37da2899SCharles.Forsyth}
106*37da2899SCharles.Forsyth
107*37da2899SCharles.ForsythStyxserver.devauth(srv: self ref Styxserver, m: ref Tmsg.Auth)
108*37da2899SCharles.Forsyth{
109*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Error(m.tag, "authentication not required"));
110*37da2899SCharles.Forsyth}
111*37da2899SCharles.Forsyth
112*37da2899SCharles.ForsythStyxserver.devattach(srv: self ref Styxserver, m: ref Tmsg.Attach): ref Chan
113*37da2899SCharles.Forsyth{
114*37da2899SCharles.Forsyth	c := srv.newchan(m.fid);
115*37da2899SCharles.Forsyth	if (c == nil) {
116*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Einuse));
117*37da2899SCharles.Forsyth		return nil;
118*37da2899SCharles.Forsyth	}
119*37da2899SCharles.Forsyth	c.uname = m.uname;
120*37da2899SCharles.Forsyth	c.qid.qtype = Sys->QTDIR;
121*37da2899SCharles.Forsyth	c.qid.path = big 0;
122*37da2899SCharles.Forsyth	c.path = "dev";
123*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Attach(m.tag, c.qid));
124*37da2899SCharles.Forsyth	return c;
125*37da2899SCharles.Forsyth}
126*37da2899SCharles.Forsyth
127*37da2899SCharles.ForsythStyxserver.clone(srv: self ref Styxserver, oc: ref Chan, newfid: int): ref Chan
128*37da2899SCharles.Forsyth{
129*37da2899SCharles.Forsyth	c := srv.newchan(newfid);
130*37da2899SCharles.Forsyth	if (c == nil)
131*37da2899SCharles.Forsyth		return nil;
132*37da2899SCharles.Forsyth	c.qid = oc.qid;
133*37da2899SCharles.Forsyth	c.uname  = oc.uname;
134*37da2899SCharles.Forsyth	c.open = oc.open;
135*37da2899SCharles.Forsyth	c.mode = oc.mode;
136*37da2899SCharles.Forsyth	c.path = oc.path;
137*37da2899SCharles.Forsyth	c.data = oc.data;
138*37da2899SCharles.Forsyth	return c;
139*37da2899SCharles.Forsyth}
140*37da2899SCharles.Forsyth
141*37da2899SCharles.ForsythStyxserver.devflush(srv: self ref Styxserver, m: ref Tmsg.Flush)
142*37da2899SCharles.Forsyth{
143*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Flush(m.tag));
144*37da2899SCharles.Forsyth}
145*37da2899SCharles.Forsyth
146*37da2899SCharles.ForsythStyxserver.devwalk(srv: self ref Styxserver, m: ref Tmsg.Walk,
147*37da2899SCharles.Forsyth							gen: Dirgenmod, tab: array of Dirtab): ref Chan
148*37da2899SCharles.Forsyth{
149*37da2899SCharles.Forsyth	c := srv.fidtochan(m.fid);
150*37da2899SCharles.Forsyth	if (c == nil) {
151*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
152*37da2899SCharles.Forsyth		return nil;
153*37da2899SCharles.Forsyth	}
154*37da2899SCharles.Forsyth	if (c.open) {
155*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Eopen));
156*37da2899SCharles.Forsyth		return nil;
157*37da2899SCharles.Forsyth	}
158*37da2899SCharles.Forsyth	if (!c.isdir()) {
159*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Enotdir));
160*37da2899SCharles.Forsyth		return nil;
161*37da2899SCharles.Forsyth	}
162*37da2899SCharles.Forsyth	# should check permissions here?
163*37da2899SCharles.Forsyth	qids: array of Sys->Qid;
164*37da2899SCharles.Forsyth	cc := ref *c;	# walk a temporary copy
165*37da2899SCharles.Forsyth	if(len m.names > 0){
166*37da2899SCharles.Forsyth		qids = array[len m.names] of Sys->Qid;
167*37da2899SCharles.Forsyth		for(i := 0; i < len m.names; i++){
168*37da2899SCharles.Forsyth			for(k := 0;; k++){
169*37da2899SCharles.Forsyth				(ok, d) := gen->dirgen(srv, cc, tab, k);
170*37da2899SCharles.Forsyth				if(ok < 0){
171*37da2899SCharles.Forsyth					if(i == 0)
172*37da2899SCharles.Forsyth						srv.reply(ref Rmsg.Error(m.tag, Enotfound));
173*37da2899SCharles.Forsyth					else
174*37da2899SCharles.Forsyth						srv.reply(ref Rmsg.Walk(m.tag, qids[0:i]));
175*37da2899SCharles.Forsyth					return nil;
176*37da2899SCharles.Forsyth				}
177*37da2899SCharles.Forsyth				if (d.name == m.names[i]) {
178*37da2899SCharles.Forsyth					cc.qid = d.qid;
179*37da2899SCharles.Forsyth					cc.path = d.name;
180*37da2899SCharles.Forsyth					qids[i] = cc.qid;
181*37da2899SCharles.Forsyth					break;
182*37da2899SCharles.Forsyth				}
183*37da2899SCharles.Forsyth			}
184*37da2899SCharles.Forsyth		}
185*37da2899SCharles.Forsyth	}
186*37da2899SCharles.Forsyth	# successful walk
187*37da2899SCharles.Forsyth	if(m.newfid != m.fid){
188*37da2899SCharles.Forsyth		# clone/walk
189*37da2899SCharles.Forsyth		nc := srv.clone(cc, m.newfid);
190*37da2899SCharles.Forsyth		if(nc == nil){
191*37da2899SCharles.Forsyth			srv.reply(ref Rmsg.Error(m.tag, Einuse));
192*37da2899SCharles.Forsyth			return nil;
193*37da2899SCharles.Forsyth		}
194*37da2899SCharles.Forsyth		c = nc;
195*37da2899SCharles.Forsyth	}else{
196*37da2899SCharles.Forsyth		# walk c itself
197*37da2899SCharles.Forsyth		c.qid = cc.qid;
198*37da2899SCharles.Forsyth		c.path = cc.path;
199*37da2899SCharles.Forsyth	}
200*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Walk(m.tag, qids));
201*37da2899SCharles.Forsyth	return c;
202*37da2899SCharles.Forsyth}
203*37da2899SCharles.Forsyth
204*37da2899SCharles.ForsythStyxserver.devclunk(srv: self ref Styxserver, m: ref Tmsg.Clunk): ref Chan
205*37da2899SCharles.Forsyth{
206*37da2899SCharles.Forsyth	c := srv.fidtochan(m.fid);
207*37da2899SCharles.Forsyth	if (c == nil) {
208*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
209*37da2899SCharles.Forsyth		return nil;
210*37da2899SCharles.Forsyth	}
211*37da2899SCharles.Forsyth	srv.chanfree(c);
212*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Clunk(m.tag));
213*37da2899SCharles.Forsyth	return c;
214*37da2899SCharles.Forsyth}
215*37da2899SCharles.Forsyth
216*37da2899SCharles.ForsythStyxserver.devstat(srv: self ref Styxserver, m: ref Tmsg.Stat,
217*37da2899SCharles.Forsyth							gen: Dirgenmod, tab: array of Dirtab)
218*37da2899SCharles.Forsyth{
219*37da2899SCharles.Forsyth	c := srv.fidtochan(m.fid);
220*37da2899SCharles.Forsyth	if (c == nil) {
221*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
222*37da2899SCharles.Forsyth		return;
223*37da2899SCharles.Forsyth	}
224*37da2899SCharles.Forsyth	i := 0;
225*37da2899SCharles.Forsyth	(ok, d) := gen->dirgen(srv, c, tab, i++);
226*37da2899SCharles.Forsyth	while (ok >= 0) {
227*37da2899SCharles.Forsyth		if (ok > 0 && c.qid.path == d.qid.path) {
228*37da2899SCharles.Forsyth			srv.reply(ref Rmsg.Stat(m.tag, d));
229*37da2899SCharles.Forsyth			return;
230*37da2899SCharles.Forsyth		}
231*37da2899SCharles.Forsyth		(ok, d) = gen->dirgen(srv, c, tab, i++);
232*37da2899SCharles.Forsyth	}
233*37da2899SCharles.Forsyth	# auto-generate entry for directory if not found.
234*37da2899SCharles.Forsyth	# XXX this is asking for trouble, as the permissions given
235*37da2899SCharles.Forsyth	# on stat() of a directory can be different from those given
236*37da2899SCharles.Forsyth	# when reading the directory's entry in its parent dir.
237*37da2899SCharles.Forsyth	if (c.qid.qtype & Sys->QTDIR)
238*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Stat(m.tag, devdir(c, c.qid, c.path, big 0, srv.uname, Sys->DMDIR|8r555)));
239*37da2899SCharles.Forsyth	else
240*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Enotfound));
241*37da2899SCharles.Forsyth}
242*37da2899SCharles.Forsyth
243*37da2899SCharles.ForsythStyxserver.devdirread(srv: self ref Styxserver, m: ref Tmsg.Read,
244*37da2899SCharles.Forsyth							gen: Dirgenmod, tab: array of Dirtab)
245*37da2899SCharles.Forsyth{
246*37da2899SCharles.Forsyth	c := srv.fidtochan(m.fid);
247*37da2899SCharles.Forsyth	if (c == nil) {
248*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
249*37da2899SCharles.Forsyth		return;
250*37da2899SCharles.Forsyth	}
251*37da2899SCharles.Forsyth	offset := int m.offset;
252*37da2899SCharles.Forsyth	data := array[m.count] of byte;
253*37da2899SCharles.Forsyth	start := 0;
254*37da2899SCharles.Forsyth	n := 0;
255*37da2899SCharles.Forsyth	for (k := 0;; k++) {
256*37da2899SCharles.Forsyth		(ok, d) := gen->dirgen(srv, c, tab, k);
257*37da2899SCharles.Forsyth		if(ok < 0){
258*37da2899SCharles.Forsyth			srv.reply(ref Rmsg.Read(m.tag, data[0:n]));
259*37da2899SCharles.Forsyth			return;
260*37da2899SCharles.Forsyth		}
261*37da2899SCharles.Forsyth		size := styx->packdirsize(d);
262*37da2899SCharles.Forsyth		if(start < offset){
263*37da2899SCharles.Forsyth			start += size;
264*37da2899SCharles.Forsyth			continue;
265*37da2899SCharles.Forsyth		}
266*37da2899SCharles.Forsyth		if(n+size > m.count)
267*37da2899SCharles.Forsyth			break;
268*37da2899SCharles.Forsyth		data[n:] = styx->packdir(d);
269*37da2899SCharles.Forsyth		n += size;
270*37da2899SCharles.Forsyth	}
271*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Read(m.tag, data[0:n]));
272*37da2899SCharles.Forsyth}
273*37da2899SCharles.Forsyth
274*37da2899SCharles.ForsythStyxserver.devopen(srv: self ref Styxserver, m: ref Tmsg.Open,
275*37da2899SCharles.Forsyth							gen: Dirgenmod, tab: array of Dirtab): ref Chan
276*37da2899SCharles.Forsyth{
277*37da2899SCharles.Forsyth	c := srv.fidtochan(m.fid);
278*37da2899SCharles.Forsyth	if (c == nil) {
279*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
280*37da2899SCharles.Forsyth		return nil;
281*37da2899SCharles.Forsyth	}
282*37da2899SCharles.Forsyth	omode := m.mode;
283*37da2899SCharles.Forsyth	i := 0;
284*37da2899SCharles.Forsyth	(ok, d) := gen->dirgen(srv, c, tab, i++);
285*37da2899SCharles.Forsyth	while (ok >= 0) {
286*37da2899SCharles.Forsyth		# XXX dev.c checks vers as well... is that desirable?
287*37da2899SCharles.Forsyth		if (ok > 0 && c.qid.path == d.qid.path) {
288*37da2899SCharles.Forsyth			if (openok(omode, d.mode, c.uname, d.uid, d.gid)) {
289*37da2899SCharles.Forsyth				c.qid.vers = d.qid.vers;
290*37da2899SCharles.Forsyth				break;
291*37da2899SCharles.Forsyth			}
292*37da2899SCharles.Forsyth			srv.reply(ref Rmsg.Error(m.tag, Eperm));
293*37da2899SCharles.Forsyth			return nil;
294*37da2899SCharles.Forsyth		}
295*37da2899SCharles.Forsyth		(ok, d) = gen->dirgen(srv, c, tab, i++);
296*37da2899SCharles.Forsyth	}
297*37da2899SCharles.Forsyth	if ((c.qid.qtype & Sys->QTDIR) && omode != Sys->OREAD) {
298*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Eperm));
299*37da2899SCharles.Forsyth		return nil;
300*37da2899SCharles.Forsyth	}
301*37da2899SCharles.Forsyth	if ((c.mode = openmode(omode)) == -1) {
302*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadarg));
303*37da2899SCharles.Forsyth		return nil;
304*37da2899SCharles.Forsyth	}
305*37da2899SCharles.Forsyth	c.open = 1;
306*37da2899SCharles.Forsyth	c.mode = omode;
307*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Open(m.tag, c.qid, Styx->MAXFDATA));
308*37da2899SCharles.Forsyth	return c;
309*37da2899SCharles.Forsyth}
310*37da2899SCharles.Forsyth
311*37da2899SCharles.ForsythStyxserver.devremove(srv: self ref Styxserver, m: ref Tmsg.Remove): ref Chan
312*37da2899SCharles.Forsyth{
313*37da2899SCharles.Forsyth	c := srv.fidtochan(m.fid);
314*37da2899SCharles.Forsyth	if (c == nil) {
315*37da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
316*37da2899SCharles.Forsyth		return nil;
317*37da2899SCharles.Forsyth	}
318*37da2899SCharles.Forsyth	srv.chanfree(c);
319*37da2899SCharles.Forsyth	srv.reply(ref Rmsg.Error(m.tag, Eperm));
320*37da2899SCharles.Forsyth	return c;
321*37da2899SCharles.Forsyth}
322*37da2899SCharles.Forsyth
323*37da2899SCharles.ForsythStyxserver.fidtochan(srv: self ref Styxserver, fid: int): ref Chan
324*37da2899SCharles.Forsyth{
325*37da2899SCharles.Forsyth	for (l := srv.chans[fid & (CHANHASHSIZE-1)]; l != nil; l = tl l)
326*37da2899SCharles.Forsyth		if ((hd l).fid == fid)
327*37da2899SCharles.Forsyth			return hd l;
328*37da2899SCharles.Forsyth	return nil;
329*37da2899SCharles.Forsyth}
330*37da2899SCharles.Forsyth
331*37da2899SCharles.ForsythStyxserver.chanfree(srv: self ref Styxserver, c: ref Chan)
332*37da2899SCharles.Forsyth{
333*37da2899SCharles.Forsyth	slot := c.fid & (CHANHASHSIZE-1);
334*37da2899SCharles.Forsyth	nl: list of ref Chan;
335*37da2899SCharles.Forsyth	for (l := srv.chans[slot]; l != nil; l = tl l)
336*37da2899SCharles.Forsyth		if ((hd l).fid != c.fid)
337*37da2899SCharles.Forsyth			nl = (hd l) :: nl;
338*37da2899SCharles.Forsyth	srv.chans[slot] = nl;
339*37da2899SCharles.Forsyth}
340*37da2899SCharles.Forsyth
341*37da2899SCharles.ForsythStyxserver.chanlist(srv: self ref Styxserver): list of ref Chan
342*37da2899SCharles.Forsyth{
343*37da2899SCharles.Forsyth	cl: list of ref Chan;
344*37da2899SCharles.Forsyth	for (i := 0; i < len srv.chans; i++)
345*37da2899SCharles.Forsyth		for (l := srv.chans[i]; l != nil; l = tl l)
346*37da2899SCharles.Forsyth			cl = hd l :: cl;
347*37da2899SCharles.Forsyth	return cl;
348*37da2899SCharles.Forsyth}
349*37da2899SCharles.Forsyth
350*37da2899SCharles.ForsythStyxserver.newchan(srv: self ref Styxserver, fid: int): ref Chan
351*37da2899SCharles.Forsyth{
352*37da2899SCharles.Forsyth	# fid already in use
353*37da2899SCharles.Forsyth	if ((c := srv.fidtochan(fid)) != nil)
354*37da2899SCharles.Forsyth		return nil;
355*37da2899SCharles.Forsyth	c = ref Chan;
356*37da2899SCharles.Forsyth	c.qid = Sys->Qid(big 0, 0, Sys->QTFILE);
357*37da2899SCharles.Forsyth	c.open = 0;
358*37da2899SCharles.Forsyth	c.mode = 0;
359*37da2899SCharles.Forsyth	c.fid = fid;
360*37da2899SCharles.Forsyth	slot := fid & (CHANHASHSIZE-1);
361*37da2899SCharles.Forsyth	srv.chans[slot] = c :: srv.chans[slot];
362*37da2899SCharles.Forsyth	return c;
363*37da2899SCharles.Forsyth}
364*37da2899SCharles.Forsyth
365*37da2899SCharles.Forsythdevdir(nil: ref Chan, qid: Sys->Qid, name: string, length: big,
366*37da2899SCharles.Forsyth				user: string, perm: int): Sys->Dir
367*37da2899SCharles.Forsyth{
368*37da2899SCharles.Forsyth	d: Sys->Dir;
369*37da2899SCharles.Forsyth	d.name = name;
370*37da2899SCharles.Forsyth	d.qid = qid;
371*37da2899SCharles.Forsyth	d.dtype = 'X';
372*37da2899SCharles.Forsyth	d.dev = 0;		# XXX what should this be?
373*37da2899SCharles.Forsyth	d.mode = perm;
374*37da2899SCharles.Forsyth	if (qid.qtype & Sys->QTDIR)
375*37da2899SCharles.Forsyth		d.mode |= Sys->DMDIR;
376*37da2899SCharles.Forsyth	d.atime = starttime;	# XXX should be better than this.
377*37da2899SCharles.Forsyth	d.mtime = starttime;
378*37da2899SCharles.Forsyth	d.length = length;
379*37da2899SCharles.Forsyth	d.uid = user;
380*37da2899SCharles.Forsyth	d.gid = user;
381*37da2899SCharles.Forsyth	return d;
382*37da2899SCharles.Forsyth}
383*37da2899SCharles.Forsyth
384*37da2899SCharles.Forsythreadbytes(m: ref Tmsg.Read, d: array of byte): ref Rmsg.Read
385*37da2899SCharles.Forsyth{
386*37da2899SCharles.Forsyth	r := ref Rmsg.Read(m.tag, nil);
387*37da2899SCharles.Forsyth	offset := int m.offset;
388*37da2899SCharles.Forsyth	if (offset >= len d)
389*37da2899SCharles.Forsyth		return r;
390*37da2899SCharles.Forsyth	e := offset + m.count;
391*37da2899SCharles.Forsyth	if (e > len d)
392*37da2899SCharles.Forsyth		e = len d;
393*37da2899SCharles.Forsyth	r.data = d[offset:e];
394*37da2899SCharles.Forsyth	return r;
395*37da2899SCharles.Forsyth}
396*37da2899SCharles.Forsyth
397*37da2899SCharles.Forsythreadnum(m: ref Tmsg.Read, val, size: int): ref Rmsg.Read
398*37da2899SCharles.Forsyth{
399*37da2899SCharles.Forsyth	return readbytes(m, sys->aprint("%-*d", size, val));
400*37da2899SCharles.Forsyth}
401*37da2899SCharles.Forsyth
402*37da2899SCharles.Forsythreadstr(m: ref Tmsg.Read, d: string): ref Rmsg.Read
403*37da2899SCharles.Forsyth{
404*37da2899SCharles.Forsyth	return readbytes(m, array of byte d);
405*37da2899SCharles.Forsyth}
406*37da2899SCharles.Forsyth
407*37da2899SCharles.Forsythdirgenmodule(): Dirgenmod
408*37da2899SCharles.Forsyth{
409*37da2899SCharles.Forsyth	return load Dirgenmod "$self";
410*37da2899SCharles.Forsyth}
411*37da2899SCharles.Forsyth
412*37da2899SCharles.Forsythdirgen(srv: ref Styxserver, c: ref Styxlib->Chan,
413*37da2899SCharles.Forsyth				tab: array of Dirtab, i: int): (int, Sys->Dir)
414*37da2899SCharles.Forsyth{
415*37da2899SCharles.Forsyth	d: Sys->Dir;
416*37da2899SCharles.Forsyth	if (tab == nil || i >= len tab)
417*37da2899SCharles.Forsyth		return (-1, d);
418*37da2899SCharles.Forsyth	return (1, devdir(c, tab[i].qid, tab[i].name, tab[i].length, srv.uname, tab[i].perm));
419*37da2899SCharles.Forsyth}
420*37da2899SCharles.Forsyth
421*37da2899SCharles.Forsythopenmode(o: int): int
422*37da2899SCharles.Forsyth{
423*37da2899SCharles.Forsyth	OTRUNC, ORCLOSE, OREAD, ORDWR: import Sys;
424*37da2899SCharles.Forsyth	if(o >= (OTRUNC|ORCLOSE|ORDWR))
425*37da2899SCharles.Forsyth		return -1;
426*37da2899SCharles.Forsyth	o &= ~(OTRUNC|ORCLOSE);
427*37da2899SCharles.Forsyth	if(o > ORDWR)
428*37da2899SCharles.Forsyth		return -1;
429*37da2899SCharles.Forsyth	return o;
430*37da2899SCharles.Forsyth}
431*37da2899SCharles.Forsyth
432*37da2899SCharles.Forsythaccess := array[] of {8r400, 8r200, 8r600, 8r100};
433*37da2899SCharles.Forsythopenok(omode, perm: int, uname, funame, nil: string): int
434*37da2899SCharles.Forsyth{
435*37da2899SCharles.Forsyth	# XXX what should we do about groups?
436*37da2899SCharles.Forsyth	# this is inadequate anyway:
437*37da2899SCharles.Forsyth	# OTRUNC
438*37da2899SCharles.Forsyth	# user should be allowed to open it if permission
439*37da2899SCharles.Forsyth	# is allowed to others.
440*37da2899SCharles.Forsyth	mode: int;
441*37da2899SCharles.Forsyth	if (uname == funame)
442*37da2899SCharles.Forsyth		mode = perm;
443*37da2899SCharles.Forsyth	else
444*37da2899SCharles.Forsyth		mode = perm << 6;
445*37da2899SCharles.Forsyth
446*37da2899SCharles.Forsyth	t := access[omode & 3];
447*37da2899SCharles.Forsyth	return ((t & mode) == t);
448*37da2899SCharles.Forsyth}
449*37da2899SCharles.Forsyth
450*37da2899SCharles.ForsythChan.isdir(c: self ref Chan): int
451*37da2899SCharles.Forsyth{
452*37da2899SCharles.Forsyth	return (c.qid.qtype & Sys->QTDIR) != 0;
453*37da2899SCharles.Forsyth}
454