xref: /inferno-os/appl/lib/styxservers.b (revision ad4c862fd80d3ad38a6464a9ea169a78354a77fc)
137da2899SCharles.Forsythimplement Styxservers;
237da2899SCharles.Forsyth
337da2899SCharles.Forsyth#
437da2899SCharles.Forsyth# Copyright © 1999 Vita Nuova Limited.  All rights reserved.
537da2899SCharles.Forsyth# Revisions copyright © 2000-2003 Vita Nuova Holdings Limited.  All rights reserved.
637da2899SCharles.Forsyth#
737da2899SCharles.Forsyth#	Derived from Roger Peppe's Styxlib by Martin C. Atkins, 2001/2002 by
837da2899SCharles.Forsyth#	adding new helper functions, and then removing Dirgenmod and its helpers
937da2899SCharles.Forsyth#
1037da2899SCharles.Forsyth#	Further modified by Roger Peppe to simplify the interface by
1137da2899SCharles.Forsyth#	adding the Navigator/Navop channel interface and making other changes,
1237da2899SCharles.Forsyth#	including using the Styx module
1337da2899SCharles.Forsyth#
1437da2899SCharles.Forsyth# converted to revised Styx at Vita Nuova
1537da2899SCharles.Forsyth# further revised August/September 2002
1637da2899SCharles.Forsyth#
1737da2899SCharles.Forsyth# TO DO:
1837da2899SCharles.Forsyth#	- directory reading interface revision?
1937da2899SCharles.Forsyth#
2037da2899SCharles.Forsyth
2137da2899SCharles.Forsythinclude "sys.m";
2237da2899SCharles.Forsyth	sys: Sys;
2337da2899SCharles.Forsyth
2437da2899SCharles.Forsythinclude "styx.m";
2537da2899SCharles.Forsyth	styx: Styx;
2637da2899SCharles.Forsyth	Tmsg, Rmsg: import styx;
2737da2899SCharles.Forsyth
2837da2899SCharles.Forsythinclude "styxservers.m";
2937da2899SCharles.Forsyth
3037da2899SCharles.ForsythCHANHASHSIZE: con 32;
3137da2899SCharles.ForsythDIRREADSIZE: con Styx->STATFIXLEN+4*20;	# ``reasonable'' chunk for reading directories
3237da2899SCharles.Forsyth
3337da2899SCharles.Forsythdebug := 0;
3437da2899SCharles.Forsyth
3537da2899SCharles.Forsythinit(styxmod: Styx)
3637da2899SCharles.Forsyth{
3737da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
3837da2899SCharles.Forsyth	styx = styxmod;
3937da2899SCharles.Forsyth}
4037da2899SCharles.Forsyth
4137da2899SCharles.Forsythtraceset(d: int)
4237da2899SCharles.Forsyth{
4337da2899SCharles.Forsyth	debug = d;
4437da2899SCharles.Forsyth}
4537da2899SCharles.Forsyth
4637da2899SCharles.ForsythStyxserver.new(fd: ref Sys->FD, t: ref Navigator, rootpath: big): (chan of ref Tmsg, ref Styxserver)
4737da2899SCharles.Forsyth{
4837da2899SCharles.Forsyth	tchan := chan of ref Tmsg;
4937da2899SCharles.Forsyth	srv := ref Styxserver(fd, array[CHANHASHSIZE] of list of ref Fid, chan[1] of int, t, rootpath, 0, nil);
5037da2899SCharles.Forsyth
5137da2899SCharles.Forsyth	sync := chan of int;
5237da2899SCharles.Forsyth	spawn tmsgreader(fd, srv, tchan, sync);
5337da2899SCharles.Forsyth	<-sync;
5437da2899SCharles.Forsyth	return (tchan, srv);
5537da2899SCharles.Forsyth}
5637da2899SCharles.Forsyth
5737da2899SCharles.Forsythtmsgreader(fd: ref Sys->FD, srv: ref Styxserver, tchan: chan of ref Tmsg, sync: chan of int)
5837da2899SCharles.Forsyth{
5937da2899SCharles.Forsyth	if(debug)
6037da2899SCharles.Forsyth		sys->pctl(Sys->NEWFD|Sys->NEWNS, fd.fd :: 2 :: nil);
6137da2899SCharles.Forsyth	else
6237da2899SCharles.Forsyth		sys->pctl(Sys->NEWFD|Sys->NEWNS, fd.fd :: nil);
6337da2899SCharles.Forsyth	sync <-= 1;
6437da2899SCharles.Forsyth	fd = sys->fildes(fd.fd);
6537da2899SCharles.Forsyth	m: ref Tmsg;
6637da2899SCharles.Forsyth	do {
6737da2899SCharles.Forsyth		m = Tmsg.read(fd, srv.msize);
6837da2899SCharles.Forsyth		if(debug && m != nil)
6937da2899SCharles.Forsyth			sys->fprint(sys->fildes(2), "<- %s\n", m.text());
7037da2899SCharles.Forsyth		tchan <-= m;
7137da2899SCharles.Forsyth	} while(m != nil && tagof(m) != tagof(Tmsg.Readerror));
7237da2899SCharles.Forsyth}
7337da2899SCharles.Forsyth
7437da2899SCharles.ForsythFid.clone(oc: self ref Fid, c: ref Fid): ref Fid
7537da2899SCharles.Forsyth{
7637da2899SCharles.Forsyth	# c.fid not touched, other values copied from c
7737da2899SCharles.Forsyth	c.path = oc.path;
7837da2899SCharles.Forsyth	c.qtype = oc.qtype;
7937da2899SCharles.Forsyth	c.isopen = oc.isopen;
8037da2899SCharles.Forsyth	c.mode = oc.mode;
8137da2899SCharles.Forsyth	c.doffset = oc.doffset;
8237da2899SCharles.Forsyth	c.uname  = oc.uname;
8337da2899SCharles.Forsyth	c.param = oc.param;
8437da2899SCharles.Forsyth	c.data = oc.data;
8537da2899SCharles.Forsyth	return c;
8637da2899SCharles.Forsyth}
8737da2899SCharles.Forsyth
8837da2899SCharles.ForsythFid.walk(c: self ref Fid, qid: Sys->Qid)
8937da2899SCharles.Forsyth{
9037da2899SCharles.Forsyth	c.path = qid.path;
9137da2899SCharles.Forsyth	c.qtype = qid.qtype;
9237da2899SCharles.Forsyth}
9337da2899SCharles.Forsyth
9437da2899SCharles.ForsythFid.open(c: self ref Fid, mode: int, qid: Sys->Qid)
9537da2899SCharles.Forsyth{
9637da2899SCharles.Forsyth	c.isopen = 1;
9737da2899SCharles.Forsyth	c.mode = mode;
9837da2899SCharles.Forsyth	c.doffset = (0, 0);
9937da2899SCharles.Forsyth	c.path = qid.path;
10037da2899SCharles.Forsyth	c.qtype = qid.qtype;
10137da2899SCharles.Forsyth}
10237da2899SCharles.Forsyth
103*ad4c862fSforsythStyxserver.error(srv: self ref Styxserver, m: ref Tmsg, msg: string)
104*ad4c862fSforsyth{
105*ad4c862fSforsyth	srv.reply(ref Rmsg.Error(m.tag, msg));
106*ad4c862fSforsyth}
107*ad4c862fSforsyth
10837da2899SCharles.ForsythStyxserver.reply(srv: self ref Styxserver, m: ref Rmsg): int
10937da2899SCharles.Forsyth{
11037da2899SCharles.Forsyth	if(debug)
11137da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "-> %s\n", m.text());
11237da2899SCharles.Forsyth	if(srv.replychan != nil){
11337da2899SCharles.Forsyth		srv.replychan <-= m;
11437da2899SCharles.Forsyth		return 0;
11537da2899SCharles.Forsyth	}
11637da2899SCharles.Forsyth	return srv.replydirect(m);
11737da2899SCharles.Forsyth}
11837da2899SCharles.Forsyth
11937da2899SCharles.ForsythStyxserver.replydirect(srv: self ref Styxserver, m: ref Rmsg): int
12037da2899SCharles.Forsyth{
12137da2899SCharles.Forsyth	if(srv.msize == 0)
12237da2899SCharles.Forsyth		m = ref Rmsg.Error(m.tag, "Tversion not seen");
12337da2899SCharles.Forsyth	d := m.pack();
12437da2899SCharles.Forsyth	if(srv.msize != 0 && len d > srv.msize){
12537da2899SCharles.Forsyth		m = ref Rmsg.Error(m.tag, "Styx reply didn't fit");
12637da2899SCharles.Forsyth		d = m.pack();
12737da2899SCharles.Forsyth	}
12837da2899SCharles.Forsyth	return sys->write(srv.fd, d, len d);
12937da2899SCharles.Forsyth}
13037da2899SCharles.Forsyth
13137da2899SCharles.ForsythStyxserver.attach(srv: self ref Styxserver, m: ref Tmsg.Attach): ref Fid
13237da2899SCharles.Forsyth{
13337da2899SCharles.Forsyth	(d, err) := srv.t.stat(srv.rootpath);
13437da2899SCharles.Forsyth	if(d == nil) {
13537da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, err));
13637da2899SCharles.Forsyth		return nil;
13737da2899SCharles.Forsyth	}
13837da2899SCharles.Forsyth	if((d.qid.qtype & Sys->QTDIR) == 0) {
13937da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Enotdir));
14037da2899SCharles.Forsyth		return nil;
14137da2899SCharles.Forsyth	}
14237da2899SCharles.Forsyth	c := srv.newfid(m.fid);
14337da2899SCharles.Forsyth	if(c == nil) {
14437da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Einuse));
14537da2899SCharles.Forsyth		return nil;
14637da2899SCharles.Forsyth	}
14737da2899SCharles.Forsyth	c.uname = m.uname;
14837da2899SCharles.Forsyth	c.param = m.aname;
14937da2899SCharles.Forsyth	c.path = d.qid.path;
15037da2899SCharles.Forsyth	c.qtype = d.qid.qtype;
15137da2899SCharles.Forsyth	srv.reply(ref Rmsg.Attach(m.tag, d.qid));
15237da2899SCharles.Forsyth	return c;
15337da2899SCharles.Forsyth}
15437da2899SCharles.Forsyth
15537da2899SCharles.Forsythwalk1(n: ref Navigator, c: ref Fid, name: string): (ref Sys->Dir, string)
15637da2899SCharles.Forsyth{
15737da2899SCharles.Forsyth	(d, err) := n.stat(c.path);
15837da2899SCharles.Forsyth	if(d == nil)
15937da2899SCharles.Forsyth		return (nil, err);
16037da2899SCharles.Forsyth	if((d.qid.qtype & Sys->QTDIR) == 0)
16137da2899SCharles.Forsyth		return (nil, Enotdir);
16237da2899SCharles.Forsyth	if(!openok(c.uname, Styx->OEXEC, d.mode, d.uid, d.gid))
16337da2899SCharles.Forsyth		return (nil, Eperm);
16437da2899SCharles.Forsyth	(d, err) = n.walk(d.qid.path, name);
16537da2899SCharles.Forsyth	if(d == nil)
16637da2899SCharles.Forsyth		return (nil, err);
16737da2899SCharles.Forsyth	return (d, nil);
16837da2899SCharles.Forsyth}
16937da2899SCharles.Forsyth
17037da2899SCharles.ForsythStyxserver.walk(srv: self ref Styxserver, m: ref Tmsg.Walk): ref Fid
17137da2899SCharles.Forsyth{
17237da2899SCharles.Forsyth	c := srv.getfid(m.fid);
17337da2899SCharles.Forsyth	if(c == nil) {
17437da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
17537da2899SCharles.Forsyth		return nil;
17637da2899SCharles.Forsyth	}
17737da2899SCharles.Forsyth	if(c.isopen) {
17837da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Eopen));
17937da2899SCharles.Forsyth		return nil;
18037da2899SCharles.Forsyth	}
18137da2899SCharles.Forsyth	if(m.newfid != m.fid){
18237da2899SCharles.Forsyth		nc := srv.newfid(m.newfid);
18337da2899SCharles.Forsyth		if(nc == nil){
18437da2899SCharles.Forsyth			srv.reply(ref Rmsg.Error(m.tag, Einuse));
18537da2899SCharles.Forsyth			return nil;
18637da2899SCharles.Forsyth		}
18737da2899SCharles.Forsyth		c = c.clone(nc);
18837da2899SCharles.Forsyth	}
18937da2899SCharles.Forsyth	qids := array[len m.names] of Sys->Qid;
19037da2899SCharles.Forsyth	oldpath := c.path;
19137da2899SCharles.Forsyth	oldqtype := c.qtype;
19237da2899SCharles.Forsyth	for(i := 0; i < len m.names; i++){
19337da2899SCharles.Forsyth		(d, err) := walk1(srv.t, c, m.names[i]);
19437da2899SCharles.Forsyth		if(d == nil){
19537da2899SCharles.Forsyth			c.path = oldpath;	# restore c
19637da2899SCharles.Forsyth			c.qtype = oldqtype;
19737da2899SCharles.Forsyth			if(m.newfid != m.fid)
19837da2899SCharles.Forsyth				srv.delfid(c);
19937da2899SCharles.Forsyth			if(i == 0)
20037da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(m.tag, err));
20137da2899SCharles.Forsyth			else
20237da2899SCharles.Forsyth				srv.reply(ref Rmsg.Walk(m.tag, qids[0:i]));
20337da2899SCharles.Forsyth			return nil;
20437da2899SCharles.Forsyth		}
20537da2899SCharles.Forsyth		c.walk(d.qid);
20637da2899SCharles.Forsyth		qids[i] = d.qid;
20737da2899SCharles.Forsyth	}
20837da2899SCharles.Forsyth	srv.reply(ref Rmsg.Walk(m.tag, qids));
20937da2899SCharles.Forsyth	return c;
21037da2899SCharles.Forsyth}
21137da2899SCharles.Forsyth
21237da2899SCharles.ForsythStyxserver.canopen(srv: self ref Styxserver, m: ref Tmsg.Open): (ref Fid, int, ref Sys->Dir, string)
21337da2899SCharles.Forsyth{
21437da2899SCharles.Forsyth	c := srv.getfid(m.fid);
21537da2899SCharles.Forsyth	if(c == nil)
21637da2899SCharles.Forsyth		return (nil, 0, nil, Ebadfid);
21737da2899SCharles.Forsyth	if(c.isopen)
21837da2899SCharles.Forsyth		return (nil, 0, nil, Eopen);
21937da2899SCharles.Forsyth	(f, err) := srv.t.stat(c.path);
22037da2899SCharles.Forsyth	if(f == nil)
22137da2899SCharles.Forsyth		return (nil, 0, nil, err);
22237da2899SCharles.Forsyth	mode := openmode(m.mode);
22337da2899SCharles.Forsyth	if(mode == -1)
22437da2899SCharles.Forsyth		return (nil, 0, nil, Ebadarg);
22537da2899SCharles.Forsyth	if(mode != Sys->OREAD && f.qid.qtype & Sys->QTDIR)
22637da2899SCharles.Forsyth		return (nil, 0, nil, Eperm);
22737da2899SCharles.Forsyth	if(!openok(c.uname, m.mode, f.mode, f.uid, f.gid))
22837da2899SCharles.Forsyth		return (nil, 0, nil, Eperm);
22937da2899SCharles.Forsyth	if(m.mode & Sys->ORCLOSE) {
23037da2899SCharles.Forsyth		(dir, nil) := srv.t.walk(c.path, "..");
23137da2899SCharles.Forsyth		if(dir == nil || dir.qid.path == f.qid.path && dir.qid.qtype == f.qid.qtype ||	# can't remove root directory
23237da2899SCharles.Forsyth		   !openok(c.uname, Sys->OWRITE, dir.mode, dir.uid, dir.gid))
23337da2899SCharles.Forsyth			return (nil, 0, nil, Eperm);
23437da2899SCharles.Forsyth		mode |= Sys->ORCLOSE;
23537da2899SCharles.Forsyth	}
23637da2899SCharles.Forsyth	return (c, mode, f, err);
23737da2899SCharles.Forsyth}
23837da2899SCharles.Forsyth
23937da2899SCharles.ForsythStyxserver.open(srv: self ref Styxserver, m: ref Tmsg.Open): ref Fid
24037da2899SCharles.Forsyth{
24137da2899SCharles.Forsyth	(c, mode, f, err) := srv.canopen(m);
24237da2899SCharles.Forsyth	if(c == nil){
24337da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, err));
24437da2899SCharles.Forsyth		return nil;
24537da2899SCharles.Forsyth	}
24637da2899SCharles.Forsyth	c.open(mode, f.qid);
24737da2899SCharles.Forsyth	srv.reply(ref Rmsg.Open(m.tag, f.qid, srv.iounit()));
24837da2899SCharles.Forsyth	return c;
24937da2899SCharles.Forsyth}
25037da2899SCharles.Forsyth
25137da2899SCharles.ForsythStyxserver.cancreate(srv: self ref Styxserver, m: ref Tmsg.Create): (ref Fid, int, ref Sys->Dir, string)
25237da2899SCharles.Forsyth{
25337da2899SCharles.Forsyth	c := srv.getfid(m.fid);
25437da2899SCharles.Forsyth	if(c == nil)
25537da2899SCharles.Forsyth		return (nil, 0, nil, Ebadfid);
25637da2899SCharles.Forsyth	if(c.isopen)
25737da2899SCharles.Forsyth		return (nil, 0, nil, Eopen);
25837da2899SCharles.Forsyth	(d, err) := srv.t.stat(c.path);
25937da2899SCharles.Forsyth	if(d == nil)
26037da2899SCharles.Forsyth		return (nil, 0, nil, err);
26137da2899SCharles.Forsyth	if((d.mode & Sys->DMDIR) == 0)
26237da2899SCharles.Forsyth		return (nil, 0, nil, Enotdir);
26337da2899SCharles.Forsyth	if(m.name == "")
26437da2899SCharles.Forsyth		return (nil, 0, nil, Ename);
26537da2899SCharles.Forsyth	if(m.name == "." || m.name == "..")
26637da2899SCharles.Forsyth		return (nil, 0, nil, Edot);
26737da2899SCharles.Forsyth	if(!openok(c.uname, Sys->OWRITE, d.mode, d.uid, d.gid))
26837da2899SCharles.Forsyth		return (nil, 0, nil, Eperm);
26937da2899SCharles.Forsyth	if(srv.t.walk(d.qid.path, m.name).t0 != nil)
27037da2899SCharles.Forsyth		return (nil, 0, nil, Eexists);
27137da2899SCharles.Forsyth	if((mode := openmode(m.mode)) == -1)
27237da2899SCharles.Forsyth		return (nil, 0, nil, Ebadarg);
27337da2899SCharles.Forsyth	mode |= m.mode & Sys->ORCLOSE;		# can create, so directory known to be writable
27437da2899SCharles.Forsyth	f := ref Sys->zerodir;
27537da2899SCharles.Forsyth	if(m.perm & Sys->DMDIR){
27637da2899SCharles.Forsyth		f.mode = m.perm & (~8r777 | (d.mode & 8r777));
27737da2899SCharles.Forsyth		f.qid.qtype = Sys->QTDIR;
27837da2899SCharles.Forsyth	}else{
27937da2899SCharles.Forsyth		f.mode = m.perm & (~8r666 | (d.mode & 8r666));
28037da2899SCharles.Forsyth		f.qid.qtype = Sys->QTFILE;
28137da2899SCharles.Forsyth	}
28237da2899SCharles.Forsyth	f.name = m.name;
28337da2899SCharles.Forsyth	f.uid = c.uname;
28437da2899SCharles.Forsyth	f.muid = c.uname;
28537da2899SCharles.Forsyth	f.gid = d.gid;
28637da2899SCharles.Forsyth	f.dtype = d.dtype;
28737da2899SCharles.Forsyth	f.dev = d.dev;
28837da2899SCharles.Forsyth	# caller must supply atime, mtime, qid.path
28937da2899SCharles.Forsyth	return (c, mode, f, nil);
29037da2899SCharles.Forsyth}
29137da2899SCharles.Forsyth
29237da2899SCharles.ForsythStyxserver.canread(srv: self ref Styxserver, m: ref Tmsg.Read): (ref Fid, string)
29337da2899SCharles.Forsyth{
29437da2899SCharles.Forsyth	c := srv.getfid(m.fid);
29537da2899SCharles.Forsyth	if(c == nil)
29637da2899SCharles.Forsyth		return (nil, Ebadfid);
29737da2899SCharles.Forsyth	if(!c.isopen)
29837da2899SCharles.Forsyth		return (nil, Enotopen);
29937da2899SCharles.Forsyth	mode := c.mode & 3;
30037da2899SCharles.Forsyth	if(mode != Sys->OREAD && mode != Sys->ORDWR)	# readable modes
30137da2899SCharles.Forsyth		return (nil, Eaccess);
30237da2899SCharles.Forsyth	if(m.count < 0 || m.count > srv.msize-Styx->IOHDRSZ)
30337da2899SCharles.Forsyth		return (nil, Ecount);
30437da2899SCharles.Forsyth	if(m.offset < big 0)
30537da2899SCharles.Forsyth		return (nil, Eoffset);
30637da2899SCharles.Forsyth	return (c, nil);
30737da2899SCharles.Forsyth}
30837da2899SCharles.Forsyth
30937da2899SCharles.ForsythStyxserver.read(srv: self ref Styxserver, m: ref Tmsg.Read): ref Fid
31037da2899SCharles.Forsyth{
31137da2899SCharles.Forsyth	(c, err) := srv.canread(m);
31237da2899SCharles.Forsyth	if(c == nil){
31337da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, err));
31437da2899SCharles.Forsyth		return nil;
31537da2899SCharles.Forsyth	}
31637da2899SCharles.Forsyth	if((c.qtype & Sys->QTDIR) == 0) {
31737da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Eperm));
31837da2899SCharles.Forsyth		return nil;
31937da2899SCharles.Forsyth	}
32037da2899SCharles.Forsyth	if(m.count <= 0){
32137da2899SCharles.Forsyth		srv.reply(ref Rmsg.Read(m.tag, nil));
32237da2899SCharles.Forsyth		return c;
32337da2899SCharles.Forsyth	}
32437da2899SCharles.Forsyth	a := array[m.count] of byte;
32537da2899SCharles.Forsyth	(offset, index) := c.doffset;
32637da2899SCharles.Forsyth	if(int m.offset != offset){	# rescan from the beginning
32737da2899SCharles.Forsyth		offset = 0;
32837da2899SCharles.Forsyth		index = 0;
32937da2899SCharles.Forsyth	}
33037da2899SCharles.Forsyth	p := 0;
33137da2899SCharles.ForsythDread:
33237da2899SCharles.Forsyth	while((d := srv.t.readdir(c.path, index, (m.count+DIRREADSIZE-1)/DIRREADSIZE)) != nil && (nd := len d) > 0){
33337da2899SCharles.Forsyth		for(i := 0; i < nd; i++) {
33437da2899SCharles.Forsyth			size := styx->packdirsize(*d[i]);
33537da2899SCharles.Forsyth			offset += size;
33637da2899SCharles.Forsyth			index++;
33737da2899SCharles.Forsyth			if(offset < int m.offset)
33837da2899SCharles.Forsyth				continue;
33937da2899SCharles.Forsyth			if((m.count -= size) < 0){	# won't fit, save state for next time
34037da2899SCharles.Forsyth				offset -= size;
34137da2899SCharles.Forsyth				index--;
34237da2899SCharles.Forsyth				break Dread;
34337da2899SCharles.Forsyth			}
34437da2899SCharles.Forsyth			de := styx->packdir(*d[i]);
34537da2899SCharles.Forsyth			a[p:] = de;
34637da2899SCharles.Forsyth			p += size;
34737da2899SCharles.Forsyth		}
34837da2899SCharles.Forsyth	}
34937da2899SCharles.Forsyth	c.doffset = (offset, index);
35037da2899SCharles.Forsyth	srv.reply(ref Rmsg.Read(m.tag, a[0:p]));
35137da2899SCharles.Forsyth	return c;
35237da2899SCharles.Forsyth}
35337da2899SCharles.Forsyth
35437da2899SCharles.ForsythStyxserver.canwrite(srv: self ref Styxserver, m: ref Tmsg.Write): (ref Fid, string)
35537da2899SCharles.Forsyth{
35637da2899SCharles.Forsyth	c := srv.getfid(m.fid);
35737da2899SCharles.Forsyth	if(c == nil)
35837da2899SCharles.Forsyth		return (nil, Ebadfid);
35937da2899SCharles.Forsyth	if(!c.isopen)
36037da2899SCharles.Forsyth		return (nil, Enotopen);
36137da2899SCharles.Forsyth	if(c.qtype & Sys->QTDIR)
36237da2899SCharles.Forsyth		return (nil, Eperm);
36337da2899SCharles.Forsyth	mode := c.mode & 3;
36437da2899SCharles.Forsyth	if(mode != Sys->OWRITE && mode != Sys->ORDWR)	# writable modes
36537da2899SCharles.Forsyth		return (nil, Eaccess);
36637da2899SCharles.Forsyth	if(m.offset < big 0)
36737da2899SCharles.Forsyth		return (nil, Eoffset);
36837da2899SCharles.Forsyth	# could check len m.data > iounit, but since we've got it now, it doesn't matter
36937da2899SCharles.Forsyth	return (c, nil);
37037da2899SCharles.Forsyth}
37137da2899SCharles.Forsyth
37237da2899SCharles.ForsythStyxserver.stat(srv: self ref Styxserver, m: ref Tmsg.Stat)
37337da2899SCharles.Forsyth{
37437da2899SCharles.Forsyth	c := srv.getfid(m.fid);
37537da2899SCharles.Forsyth	if(c == nil) {
37637da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
37737da2899SCharles.Forsyth		return;
37837da2899SCharles.Forsyth	}
37937da2899SCharles.Forsyth	(d, err) := srv.t.stat(c.path);
38037da2899SCharles.Forsyth	if(d == nil) {
38137da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, err));
38237da2899SCharles.Forsyth		return;
38337da2899SCharles.Forsyth	}
38437da2899SCharles.Forsyth	srv.reply(ref Rmsg.Stat(m.tag, *d));
38537da2899SCharles.Forsyth}
38637da2899SCharles.Forsyth
38737da2899SCharles.ForsythStyxserver.canremove(srv: self ref Styxserver, m: ref Tmsg.Remove): (ref Fid, big, string)
38837da2899SCharles.Forsyth{
38937da2899SCharles.Forsyth	c := srv.getfid(m.fid);
39037da2899SCharles.Forsyth	if(c == nil)
39137da2899SCharles.Forsyth		return (nil, big 0, Ebadfid);
39237da2899SCharles.Forsyth	(dir, nil) := srv.t.walk(c.path, "..");	# this relies on .. working for non-directories
39337da2899SCharles.Forsyth	if(dir == nil)
39437da2899SCharles.Forsyth		return (nil, big 0, "can't find parent directory");
39537da2899SCharles.Forsyth	if(dir.qid.path == c.path && dir.qid.qtype == c.qtype ||	# can't remove root directory
39637da2899SCharles.Forsyth	   !openok(c.uname, Sys->OWRITE, dir.mode, dir.uid, dir.gid))
39737da2899SCharles.Forsyth		return (nil, big 0, Eperm);
39837da2899SCharles.Forsyth	return (c, dir.qid.path, nil);
39937da2899SCharles.Forsyth}
40037da2899SCharles.Forsyth
40137da2899SCharles.ForsythStyxserver.remove(srv: self ref Styxserver, m: ref Tmsg.Remove): ref Fid
40237da2899SCharles.Forsyth{
40337da2899SCharles.Forsyth	c := srv.getfid(m.fid);
40437da2899SCharles.Forsyth	if(c == nil) {
40537da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
40637da2899SCharles.Forsyth		return nil;
40737da2899SCharles.Forsyth	}
40837da2899SCharles.Forsyth	srv.delfid(c);			# Remove always clunks the fid
40937da2899SCharles.Forsyth	srv.reply(ref Rmsg.Error(m.tag, Eperm));
41037da2899SCharles.Forsyth	return c;
41137da2899SCharles.Forsyth}
41237da2899SCharles.Forsyth
41337da2899SCharles.ForsythStyxserver.clunk(srv: self ref Styxserver, m: ref Tmsg.Clunk): ref Fid
41437da2899SCharles.Forsyth{
41537da2899SCharles.Forsyth	c := srv.getfid(m.fid);
41637da2899SCharles.Forsyth	if(c == nil) {
41737da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Ebadfid));
41837da2899SCharles.Forsyth		return nil;
41937da2899SCharles.Forsyth	}
42037da2899SCharles.Forsyth	srv.delfid(c);
42137da2899SCharles.Forsyth	srv.reply(ref Rmsg.Clunk(m.tag));
42237da2899SCharles.Forsyth	return c;
42337da2899SCharles.Forsyth}
42437da2899SCharles.Forsyth
42537da2899SCharles.ForsythStyxserver.default(srv: self ref Styxserver, gm: ref Tmsg)
42637da2899SCharles.Forsyth{
42737da2899SCharles.Forsyth	if(gm == nil) {
42837da2899SCharles.Forsyth		srv.t.c <-= nil;
42937da2899SCharles.Forsyth		exit;
43037da2899SCharles.Forsyth	}
43137da2899SCharles.Forsyth	pick m := gm {
43237da2899SCharles.Forsyth	Readerror =>
43337da2899SCharles.Forsyth		srv.t.c <-= nil;
43437da2899SCharles.Forsyth		exit;
43537da2899SCharles.Forsyth	Version =>
43637da2899SCharles.Forsyth		if(srv.msize <= 0)
43737da2899SCharles.Forsyth			srv.msize = Styx->MAXRPC;
43837da2899SCharles.Forsyth		(msize, version) := styx->compatible(m, srv.msize, Styx->VERSION);
43937da2899SCharles.Forsyth		if(msize < 256){
44037da2899SCharles.Forsyth			srv.reply(ref Rmsg.Error(m.tag, "message size too small"));
44137da2899SCharles.Forsyth			break;
44237da2899SCharles.Forsyth		}
44337da2899SCharles.Forsyth		srv.msize = msize;
44437da2899SCharles.Forsyth		srv.reply(ref Rmsg.Version(m.tag, msize, version));
44537da2899SCharles.Forsyth	Auth =>
44637da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, "authentication not required"));
44737da2899SCharles.Forsyth	Flush =>
44837da2899SCharles.Forsyth		srv.reply(ref Rmsg.Flush(m.tag));
44937da2899SCharles.Forsyth	Walk =>
45037da2899SCharles.Forsyth		srv.walk(m);
45137da2899SCharles.Forsyth	Open =>
45237da2899SCharles.Forsyth		srv.open(m);
45337da2899SCharles.Forsyth	Create =>
45437da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Eperm));
45537da2899SCharles.Forsyth	Read =>
45637da2899SCharles.Forsyth		srv.read(m);
45737da2899SCharles.Forsyth	Write =>
45837da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Eperm));
45937da2899SCharles.Forsyth	Clunk =>
46037da2899SCharles.Forsyth		srv.clunk(m);
46137da2899SCharles.Forsyth		# to delete on ORCLOSE:
46237da2899SCharles.Forsyth		# c := srv.clunk(m);
46337da2899SCharles.Forsyth		# if(c != nil && c.mode & Sys->ORCLOSE)
46437da2899SCharles.Forsyth		# 	srv.doremove(c);
46537da2899SCharles.Forsyth	Stat =>
46637da2899SCharles.Forsyth		srv.stat(m);
46737da2899SCharles.Forsyth	Remove =>
46837da2899SCharles.Forsyth		srv.remove(m);
46937da2899SCharles.Forsyth	Wstat =>
47037da2899SCharles.Forsyth		srv.reply(ref Rmsg.Error(m.tag, Eperm));
47137da2899SCharles.Forsyth	Attach =>
47237da2899SCharles.Forsyth		srv.attach(m);
47337da2899SCharles.Forsyth	* =>
47437da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "styxservers: unhandled Tmsg tag %d - should not happen\n", tagof gm);
47537da2899SCharles.Forsyth		raise "fail: unhandled case";
47637da2899SCharles.Forsyth	}
47737da2899SCharles.Forsyth}
47837da2899SCharles.Forsyth
47937da2899SCharles.ForsythStyxserver.iounit(srv: self ref Styxserver): int
48037da2899SCharles.Forsyth{
48137da2899SCharles.Forsyth	n := srv.msize - Styx->IOHDRSZ;
48237da2899SCharles.Forsyth	if(n <= 0)
48337da2899SCharles.Forsyth		return 0;	# unknown
48437da2899SCharles.Forsyth	return n;
48537da2899SCharles.Forsyth}
48637da2899SCharles.Forsyth
48737da2899SCharles.ForsythStyxserver.getfid(srv: self ref Styxserver, fid: int): ref Fid
48837da2899SCharles.Forsyth{
48937da2899SCharles.Forsyth	# the list is safe to use without locking
49037da2899SCharles.Forsyth	for(l := srv.fids[fid & (CHANHASHSIZE-1)]; l != nil; l = tl l)
49137da2899SCharles.Forsyth		if((hd l).fid == fid)
49237da2899SCharles.Forsyth			return hd l;
49337da2899SCharles.Forsyth	return nil;
49437da2899SCharles.Forsyth}
49537da2899SCharles.Forsyth
49637da2899SCharles.ForsythStyxserver.delfid(srv: self ref Styxserver, c: ref Fid)
49737da2899SCharles.Forsyth{
49837da2899SCharles.Forsyth	slot := c.fid & (CHANHASHSIZE-1);
49937da2899SCharles.Forsyth	nl: list of ref Fid;
50037da2899SCharles.Forsyth	srv.fidlock <-= 1;
50137da2899SCharles.Forsyth	for(l := srv.fids[slot]; l != nil; l = tl l)
50237da2899SCharles.Forsyth		if((hd l).fid != c.fid)
50337da2899SCharles.Forsyth			nl = (hd l) :: nl;
50437da2899SCharles.Forsyth	srv.fids[slot] = nl;
50537da2899SCharles.Forsyth	<-srv.fidlock;
50637da2899SCharles.Forsyth}
50737da2899SCharles.Forsyth
50837da2899SCharles.ForsythStyxserver.allfids(srv: self ref Styxserver): list of ref Fid
50937da2899SCharles.Forsyth{
51037da2899SCharles.Forsyth	cl: list of ref Fid;
51137da2899SCharles.Forsyth	srv.fidlock <-= 1;
51237da2899SCharles.Forsyth	for(i := 0; i < len srv.fids; i++)
51337da2899SCharles.Forsyth		for(l := srv.fids[i]; l != nil; l = tl l)
51437da2899SCharles.Forsyth			cl = hd l :: cl;
51537da2899SCharles.Forsyth	<-srv.fidlock;
51637da2899SCharles.Forsyth	return cl;
51737da2899SCharles.Forsyth}
51837da2899SCharles.Forsyth
51937da2899SCharles.ForsythStyxserver.newfid(srv: self ref Styxserver, fid: int): ref Fid
52037da2899SCharles.Forsyth{
52137da2899SCharles.Forsyth	srv.fidlock <-= 1;
52237da2899SCharles.Forsyth	if((c := srv.getfid(fid)) != nil){
52337da2899SCharles.Forsyth		<-srv.fidlock;
52437da2899SCharles.Forsyth		return nil;		# illegal: fid in use
52537da2899SCharles.Forsyth	}
52637da2899SCharles.Forsyth	c = ref Fid;
52737da2899SCharles.Forsyth	c.path = big -1;
52837da2899SCharles.Forsyth	c.qtype = 0;
52937da2899SCharles.Forsyth	c.isopen = 0;
53037da2899SCharles.Forsyth	c.mode = 0;
53137da2899SCharles.Forsyth	c.fid = fid;
53237da2899SCharles.Forsyth	c.doffset = (0, 0);
53337da2899SCharles.Forsyth	slot := fid & (CHANHASHSIZE-1);
53437da2899SCharles.Forsyth	srv.fids[slot] = c :: srv.fids[slot];
53537da2899SCharles.Forsyth	<-srv.fidlock;
53637da2899SCharles.Forsyth	return c;
53737da2899SCharles.Forsyth}
53837da2899SCharles.Forsyth
53937da2899SCharles.Forsythreadstr(m: ref Tmsg.Read, d: string): ref Rmsg.Read
54037da2899SCharles.Forsyth{
54137da2899SCharles.Forsyth	return readbytes(m, array of byte d);
54237da2899SCharles.Forsyth}
54337da2899SCharles.Forsyth
54437da2899SCharles.Forsythreadbytes(m: ref Tmsg.Read, d: array of byte): ref Rmsg.Read
54537da2899SCharles.Forsyth{
54637da2899SCharles.Forsyth	r := ref Rmsg.Read(m.tag, nil);
54737da2899SCharles.Forsyth	if(m.offset >= big len d || m.offset < big 0)
54837da2899SCharles.Forsyth		return r;
54937da2899SCharles.Forsyth	offset := int m.offset;
55037da2899SCharles.Forsyth	e := offset + m.count;
55137da2899SCharles.Forsyth	if(e > len d)
55237da2899SCharles.Forsyth		e = len d;
55337da2899SCharles.Forsyth	r.data = d[offset:e];
55437da2899SCharles.Forsyth	return r;
55537da2899SCharles.Forsyth}
55637da2899SCharles.Forsyth
55737da2899SCharles.ForsythNavigator.new(c: chan of ref Navop): ref Navigator
55837da2899SCharles.Forsyth{
55937da2899SCharles.Forsyth	return ref Navigator(c, chan of (ref Sys->Dir, string));
56037da2899SCharles.Forsyth}
56137da2899SCharles.Forsyth
56237da2899SCharles.ForsythNavigator.stat(t: self ref Navigator, q: big): (ref Sys->Dir, string)
56337da2899SCharles.Forsyth{
56437da2899SCharles.Forsyth	t.c <-= ref Navop.Stat(t.reply, q);
56537da2899SCharles.Forsyth	return <-t.reply;
56637da2899SCharles.Forsyth}
56737da2899SCharles.Forsyth
56837da2899SCharles.ForsythNavigator.walk(t: self ref Navigator, q: big, name: string): (ref Sys->Dir, string)
56937da2899SCharles.Forsyth{
57037da2899SCharles.Forsyth	t.c <-= ref Navop.Walk(t.reply, q, name);
57137da2899SCharles.Forsyth	return <-t.reply;
57237da2899SCharles.Forsyth}
57337da2899SCharles.Forsyth
57437da2899SCharles.ForsythNavigator.readdir(t: self ref Navigator, q: big, offset, count: int): array of ref Sys->Dir
57537da2899SCharles.Forsyth{
57637da2899SCharles.Forsyth	a := array[count] of ref Sys->Dir;
57737da2899SCharles.Forsyth	t.c <-= ref Navop.Readdir(t.reply, q, offset, count);
57837da2899SCharles.Forsyth	i := 0;
57937da2899SCharles.Forsyth	while((d := (<-t.reply).t0) != nil)
58037da2899SCharles.Forsyth		if(i < count)
58137da2899SCharles.Forsyth			a[i++] = d;
58237da2899SCharles.Forsyth	if(i == 0)
58337da2899SCharles.Forsyth		return nil;
58437da2899SCharles.Forsyth	return a[0:i];
58537da2899SCharles.Forsyth}
58637da2899SCharles.Forsyth
58737da2899SCharles.Forsythopenmode(o: int): int
58837da2899SCharles.Forsyth{
58937da2899SCharles.Forsyth	OTRUNC, ORCLOSE, OREAD, ORDWR: import Sys;
59037da2899SCharles.Forsyth	o &= ~(OTRUNC|ORCLOSE);
59137da2899SCharles.Forsyth	if(o > ORDWR)
59237da2899SCharles.Forsyth		return -1;
59337da2899SCharles.Forsyth	return o;
59437da2899SCharles.Forsyth}
59537da2899SCharles.Forsyth
59637da2899SCharles.Forsythaccess := array[] of {8r400, 8r200, 8r600, 8r100};
59737da2899SCharles.Forsythopenok(uname: string, omode: int, perm: int, fuid: string, fgid: string): int
59837da2899SCharles.Forsyth{
59937da2899SCharles.Forsyth	t := access[omode & 3];
60037da2899SCharles.Forsyth	if(omode & Sys->OTRUNC){
60137da2899SCharles.Forsyth		if(perm & Sys->DMDIR)
60237da2899SCharles.Forsyth			return 0;
60337da2899SCharles.Forsyth		t |= 8r200;
60437da2899SCharles.Forsyth	}
60537da2899SCharles.Forsyth	if(uname == fuid && (t&perm) == t)
60637da2899SCharles.Forsyth		return 1;
60737da2899SCharles.Forsyth	if(uname == fgid && (t&(perm<<3)) == t)
60837da2899SCharles.Forsyth		return 1;
60937da2899SCharles.Forsyth	return (t&(perm<<6)) == t;
61037da2899SCharles.Forsyth}
611