xref: /inferno-os/appl/cmd/memfs.b (revision 3f1f06c5d12b24c4061e5123acabf72348ff45a2)
137da2899SCharles.Forsythimplement MemFS;
237da2899SCharles.Forsyth
337da2899SCharles.Forsythinclude "sys.m";
437da2899SCharles.Forsyth	sys: Sys;
537da2899SCharles.Forsyth	OTRUNC, ORCLOSE, OREAD, OWRITE: import Sys;
637da2899SCharles.Forsythinclude "styx.m";
737da2899SCharles.Forsyth	styx: Styx;
837da2899SCharles.Forsyth	Tmsg, Rmsg: import styx;
937da2899SCharles.Forsythinclude "styxlib.m";
1037da2899SCharles.Forsyth	styxlib: Styxlib;
1137da2899SCharles.Forsyth	Styxserver: import styxlib;
1237da2899SCharles.Forsythinclude "draw.m";
1337da2899SCharles.Forsythinclude "arg.m";
1437da2899SCharles.Forsyth
1537da2899SCharles.ForsythMemFS: module {
1637da2899SCharles.Forsyth	init: fn(ctxt: ref Draw->Context, args: list of string);
1737da2899SCharles.Forsyth};
1837da2899SCharles.Forsyth
1937da2899SCharles.Forsyth
2037da2899SCharles.Forsythblksz : con 512;
2137da2899SCharles.ForsythEfull : con "filesystem full";
2237da2899SCharles.Forsyth
2337da2899SCharles.ForsythMemfile : adt {
2437da2899SCharles.Forsyth	name : string;
2537da2899SCharles.Forsyth	owner : string;
2637da2899SCharles.Forsyth	qid : Sys->Qid;
2737da2899SCharles.Forsyth	perm : int;
2837da2899SCharles.Forsyth	atime : int;
2937da2899SCharles.Forsyth	mtime : int;
3037da2899SCharles.Forsyth	nopen : int;
3137da2899SCharles.Forsyth	data : array of array of byte;			# allocated in blks, no holes
3237da2899SCharles.Forsyth	length : int;
3337da2899SCharles.Forsyth	parent : cyclic ref Memfile;	# Dir entry linkage
3437da2899SCharles.Forsyth	kids : cyclic ref Memfile;
3537da2899SCharles.Forsyth	prev : cyclic ref Memfile;
3637da2899SCharles.Forsyth	next : cyclic ref Memfile;
3737da2899SCharles.Forsyth	hashnext : cyclic ref Memfile;	# Qid hash linkage
3837da2899SCharles.Forsyth};
3937da2899SCharles.Forsyth
4037da2899SCharles.ForsythQidhash : adt {
4137da2899SCharles.Forsyth	buckets : array of ref Memfile;
4237da2899SCharles.Forsyth	nextqid : int;
4337da2899SCharles.Forsyth	new : fn () : ref Qidhash;
4437da2899SCharles.Forsyth	add : fn (h : self ref Qidhash, mf : ref Memfile);
4537da2899SCharles.Forsyth	remove : fn (h : self ref Qidhash, mf : ref Memfile);
4637da2899SCharles.Forsyth	lookup : fn (h : self ref Qidhash, qid : Sys->Qid) : ref Memfile;
4737da2899SCharles.Forsyth};
4837da2899SCharles.Forsyth
4937da2899SCharles.Forsythtimefd: ref Sys->FD;
5037da2899SCharles.Forsyth
5137da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string)
5237da2899SCharles.Forsyth{
5337da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
5437da2899SCharles.Forsyth	styx = checkload(load Styx Styx->PATH, Styx->PATH);
5537da2899SCharles.Forsyth	styxlib = checkload(load Styxlib Styxlib->PATH, Styxlib->PATH);
5637da2899SCharles.Forsyth	arg := checkload(load Arg Arg->PATH, Arg->PATH);
5737da2899SCharles.Forsyth
5837da2899SCharles.Forsyth	amode := Sys->MREPL;
5937da2899SCharles.Forsyth	maxsz := 16r7fffffff;
6037da2899SCharles.Forsyth	srv := 0;
6137da2899SCharles.Forsyth	mntpt := "/tmp";
6237da2899SCharles.Forsyth
6337da2899SCharles.Forsyth	arg->init(argv);
6437da2899SCharles.Forsyth	arg->setusage("memfs [-s] [-rab] [-m size] [mountpoint]");
6537da2899SCharles.Forsyth	while((opt := arg->opt()) != 0) {
6637da2899SCharles.Forsyth		case opt{
6737da2899SCharles.Forsyth		's' =>
6837da2899SCharles.Forsyth			srv = 1;
6937da2899SCharles.Forsyth		'r' =>
7037da2899SCharles.Forsyth			amode = Sys->MREPL;
7137da2899SCharles.Forsyth		'a' =>
7237da2899SCharles.Forsyth			amode = Sys->MAFTER;
7337da2899SCharles.Forsyth		'b' =>
7437da2899SCharles.Forsyth			amode = Sys->MBEFORE;
7537da2899SCharles.Forsyth		'm' =>
7637da2899SCharles.Forsyth			maxsz = int arg->earg();
7737da2899SCharles.Forsyth		* =>
7837da2899SCharles.Forsyth			arg->usage();
7937da2899SCharles.Forsyth		}
8037da2899SCharles.Forsyth	}
8137da2899SCharles.Forsyth	argv = arg->argv();
8237da2899SCharles.Forsyth	arg = nil;
8337da2899SCharles.Forsyth	if (argv != nil)
8437da2899SCharles.Forsyth		mntpt = hd argv;
8537da2899SCharles.Forsyth
8637da2899SCharles.Forsyth	srvfd: ref Sys->FD;
8737da2899SCharles.Forsyth	mntfd: ref Sys->FD;
8837da2899SCharles.Forsyth	if (srv)
8937da2899SCharles.Forsyth		srvfd = sys->fildes(0);
9037da2899SCharles.Forsyth	else {
9137da2899SCharles.Forsyth		p := array [2] of ref Sys->FD;
9237da2899SCharles.Forsyth		if (sys->pipe(p) == -1)
9337da2899SCharles.Forsyth			error(sys->sprint("cannot create pipe: %r"));
9437da2899SCharles.Forsyth		mntfd = p[0];
9537da2899SCharles.Forsyth		srvfd = p[1];
9637da2899SCharles.Forsyth	}
9737da2899SCharles.Forsyth	styx->init();
9837da2899SCharles.Forsyth	styxlib->init(styx);
9937da2899SCharles.Forsyth	timefd = sys->open("/dev/time", sys->OREAD);
10037da2899SCharles.Forsyth
10137da2899SCharles.Forsyth	(tc, styxsrv) := Styxserver.new(srvfd);
10237da2899SCharles.Forsyth	if (srv)
10337da2899SCharles.Forsyth		memfs(maxsz, tc, styxsrv, nil);
10437da2899SCharles.Forsyth	else {
10537da2899SCharles.Forsyth		sync := chan of int;
10637da2899SCharles.Forsyth		spawn memfs(maxsz, tc, styxsrv, sync);
10737da2899SCharles.Forsyth		<-sync;
10837da2899SCharles.Forsyth		if (sys->mount(mntfd, nil, mntpt, amode | Sys->MCREATE, nil) == -1)
10937da2899SCharles.Forsyth			error(sys->sprint("failed to mount onto %s: %r", mntpt));
11037da2899SCharles.Forsyth	}
11137da2899SCharles.Forsyth}
11237da2899SCharles.Forsyth
11337da2899SCharles.Forsythcheckload[T](x: T, p: string): T
11437da2899SCharles.Forsyth{
11537da2899SCharles.Forsyth	if(x == nil)
11637da2899SCharles.Forsyth		error(sys->sprint("cannot load %s: %r", p));
11737da2899SCharles.Forsyth	return x;
11837da2899SCharles.Forsyth}
11937da2899SCharles.Forsyth
12037da2899SCharles.Forsythstderr(): ref Sys->FD
12137da2899SCharles.Forsyth{
12237da2899SCharles.Forsyth	return sys->fildes(2);
12337da2899SCharles.Forsyth}
12437da2899SCharles.Forsyth
12537da2899SCharles.Forsytherror(e: string)
12637da2899SCharles.Forsyth{
12737da2899SCharles.Forsyth	sys->fprint(stderr(), "memfs: %s\n", e);
12837da2899SCharles.Forsyth	raise "fail:error";
12937da2899SCharles.Forsyth}
13037da2899SCharles.Forsyth
13137da2899SCharles.Forsythfreeblks: int;
13237da2899SCharles.Forsyth
13337da2899SCharles.Forsythmemfs(maxsz : int, tc : chan of ref Tmsg, srv : ref Styxserver, sync: chan of int)
13437da2899SCharles.Forsyth{
13537da2899SCharles.Forsyth	sys->pctl(Sys->NEWNS, nil);
13637da2899SCharles.Forsyth	if (sync != nil)
13737da2899SCharles.Forsyth		sync <-= 1;
13837da2899SCharles.Forsyth	freeblks = (maxsz / blksz);
13937da2899SCharles.Forsyth	qhash := Qidhash.new();
14037da2899SCharles.Forsyth
14137da2899SCharles.Forsyth	# init root
14237da2899SCharles.Forsyth	root := newmf(qhash, nil, "memfs", srv.uname, 8r755 | Sys->DMDIR);
14337da2899SCharles.Forsyth	root.parent = root;
14437da2899SCharles.Forsyth
14537da2899SCharles.Forsyth	while((tmsg := <-tc) != nil) {
14637da2899SCharles.Forsyth#		sys->print("%s\n", tmsg.text());
14737da2899SCharles.Forsyth	Msg:
14837da2899SCharles.Forsyth		pick tm := tmsg {
14937da2899SCharles.Forsyth		Readerror =>
15037da2899SCharles.Forsyth			break;
15137da2899SCharles.Forsyth		Version =>
15237da2899SCharles.Forsyth			srv.devversion(tm);
15337da2899SCharles.Forsyth		Auth =>
15437da2899SCharles.Forsyth			srv.devauth(tm);
15537da2899SCharles.Forsyth		Flush =>
15637da2899SCharles.Forsyth			srv.reply(ref Rmsg.Flush(tm.tag));
15737da2899SCharles.Forsyth		Walk =>
15837da2899SCharles.Forsyth			(err, c, mf) := fidtomf(srv, qhash, tm.fid);
15937da2899SCharles.Forsyth			if (err != "") {
16037da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
16137da2899SCharles.Forsyth				continue;
16237da2899SCharles.Forsyth			}
16337da2899SCharles.Forsyth			nc: ref styxlib->Chan;
16437da2899SCharles.Forsyth			if (tm.newfid != tm.fid) {
16537da2899SCharles.Forsyth				nc = srv.clone(c, tm.newfid);
16637da2899SCharles.Forsyth				if (nc == nil) {
16737da2899SCharles.Forsyth					srv.reply(ref Rmsg.Error(tm.tag, "fid in use"));
16837da2899SCharles.Forsyth					continue;
16937da2899SCharles.Forsyth				}
17037da2899SCharles.Forsyth				c = nc;
17137da2899SCharles.Forsyth			}
17237da2899SCharles.Forsyth			qids: array of Sys->Qid;
17337da2899SCharles.Forsyth			if (len tm.names > 0) {
17437da2899SCharles.Forsyth				oqid := c.qid;
17537da2899SCharles.Forsyth				opath := c.path;
17637da2899SCharles.Forsyth				qids = array[len tm.names] of Sys->Qid;
17737da2899SCharles.Forsyth				wmf := mf;
17837da2899SCharles.Forsyth				for (i := 0; i < len tm.names; i++) {
17937da2899SCharles.Forsyth					wmf = dirlookup(wmf, tm.names[i]);
18037da2899SCharles.Forsyth					if (wmf == nil) {
18137da2899SCharles.Forsyth						if (nc == nil) {
18237da2899SCharles.Forsyth							c.qid = oqid;
18337da2899SCharles.Forsyth							c.path = opath;
18437da2899SCharles.Forsyth						} else
18537da2899SCharles.Forsyth							srv.chanfree(nc);
18637da2899SCharles.Forsyth						if (i == 0)
18737da2899SCharles.Forsyth							srv.reply(ref Rmsg.Error(tm.tag, Styxlib->Enotfound));
18837da2899SCharles.Forsyth						else
18937da2899SCharles.Forsyth							srv.reply(ref Rmsg.Walk(tm.tag, qids[0:i]));
19037da2899SCharles.Forsyth						break Msg;
19137da2899SCharles.Forsyth					}
19237da2899SCharles.Forsyth					c.qid = wmf.qid;
19337da2899SCharles.Forsyth					qids[i] = wmf.qid;
19437da2899SCharles.Forsyth				}
19537da2899SCharles.Forsyth			}
19637da2899SCharles.Forsyth			srv.reply(ref Rmsg.Walk(tm.tag, qids));
19737da2899SCharles.Forsyth		Open =>
19837da2899SCharles.Forsyth			(err, c, mf) := fidtomf(srv, qhash, tm.fid);
19937da2899SCharles.Forsyth			if (err == "" && c.open)
20037da2899SCharles.Forsyth				err = Styxlib->Eopen;
20137da2899SCharles.Forsyth			if (err == "" && !modeok(tm.mode, mf.perm, c.uname, mf.owner))
20237da2899SCharles.Forsyth				err = Styxlib->Eperm;
20337da2899SCharles.Forsyth			if (err == "" && (mf.perm & Sys->DMDIR) && (tm.mode & (OTRUNC|OWRITE|ORCLOSE)))
20437da2899SCharles.Forsyth				err = Styxlib->Eperm;
20537da2899SCharles.Forsyth			if (err == "" && (tm.mode & ORCLOSE)) {
20637da2899SCharles.Forsyth				p := mf.parent;
20737da2899SCharles.Forsyth				if (p == nil || !modeok(OWRITE, p.perm, c.uname, p.owner))
20837da2899SCharles.Forsyth					err = Styxlib->Eperm;
20937da2899SCharles.Forsyth			}
21037da2899SCharles.Forsyth
21137da2899SCharles.Forsyth			if (err != "") {
21237da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
21337da2899SCharles.Forsyth				continue;
21437da2899SCharles.Forsyth			}
21537da2899SCharles.Forsyth
21637da2899SCharles.Forsyth			c.open = 1;
21737da2899SCharles.Forsyth			c.mode = tm.mode;
21837da2899SCharles.Forsyth			c.qid.vers = mf.qid.vers;
21937da2899SCharles.Forsyth			mf.nopen++;
220*3f1f06c5SCharles.Forsyth			if ((tm.mode & OTRUNC) && !(mf.perm & Sys->DMAPPEND)) {
22137da2899SCharles.Forsyth				# OTRUNC cannot be set for a directory
22237da2899SCharles.Forsyth				# always at least one blk so don't need to check fs limit
22337da2899SCharles.Forsyth				freeblks += (len mf.data);
22437da2899SCharles.Forsyth				mf.data = nil;
22537da2899SCharles.Forsyth				freeblks--;
22637da2899SCharles.Forsyth				mf.data = array[1] of {* => array [blksz] of byte};
22737da2899SCharles.Forsyth				mf.length = 0;
22837da2899SCharles.Forsyth				mf.mtime = now();
22937da2899SCharles.Forsyth			}
23037da2899SCharles.Forsyth			srv.reply(ref Rmsg.Open(tm.tag, mf.qid, Styx->MAXFDATA));
23137da2899SCharles.Forsyth		Create =>
23237da2899SCharles.Forsyth			(err, c, parent) := fidtomf(srv, qhash, tm.fid);
23337da2899SCharles.Forsyth			if (err == "" && c.open)
23437da2899SCharles.Forsyth				err = Styxlib->Eopen;
23537da2899SCharles.Forsyth			if (err == "" && !(parent.qid.qtype & Sys->QTDIR))
23637da2899SCharles.Forsyth				err = Styxlib->Enotdir;
23737da2899SCharles.Forsyth			if (err == "" && !modeok(OWRITE, parent.perm, c.uname, parent.owner))
23837da2899SCharles.Forsyth				err = Styxlib->Eperm;
23937da2899SCharles.Forsyth			if (err == "" && (tm.perm & Sys->DMDIR) && (tm.mode & (OTRUNC|OWRITE|ORCLOSE)))
24037da2899SCharles.Forsyth				err = Styxlib->Eperm;
24137da2899SCharles.Forsyth			if (err == "" && dirlookup(parent, tm.name) != nil)
24237da2899SCharles.Forsyth				err = Styxlib->Eexists;
24337da2899SCharles.Forsyth
24437da2899SCharles.Forsyth			if (err != "") {
24537da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
24637da2899SCharles.Forsyth				continue;
24737da2899SCharles.Forsyth			}
24837da2899SCharles.Forsyth
24937da2899SCharles.Forsyth			isdir := tm.perm & Sys->DMDIR;
25037da2899SCharles.Forsyth			if (!isdir && freeblks <= 0) {
25137da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, Efull));
25237da2899SCharles.Forsyth				continue;
25337da2899SCharles.Forsyth			}
25437da2899SCharles.Forsyth
25537da2899SCharles.Forsyth			# modify perms as per Styx specification...
25637da2899SCharles.Forsyth			perm : int;
25737da2899SCharles.Forsyth			if (isdir)
25837da2899SCharles.Forsyth				perm = (tm.perm&~8r777) | (parent.perm&tm.perm&8r777);
25937da2899SCharles.Forsyth			else
26037da2899SCharles.Forsyth				perm = (tm.perm&(~8r777|8r111)) | (parent.perm&tm.perm& 8r666);
26137da2899SCharles.Forsyth
26237da2899SCharles.Forsyth			nmf := newmf(qhash, parent, tm.name, c.uname, perm);
26337da2899SCharles.Forsyth			if (!isdir) {
26437da2899SCharles.Forsyth				freeblks--;
26537da2899SCharles.Forsyth				nmf.data = array[1] of {* => array [blksz] of byte};
26637da2899SCharles.Forsyth			}
26737da2899SCharles.Forsyth
26837da2899SCharles.Forsyth			# link in the new MemFile
26937da2899SCharles.Forsyth			nmf.next = parent.kids;
27037da2899SCharles.Forsyth			if (parent.kids != nil)
27137da2899SCharles.Forsyth				parent.kids.prev = nmf;
27237da2899SCharles.Forsyth			parent.kids = nmf;
27337da2899SCharles.Forsyth
27437da2899SCharles.Forsyth			c.open = 1;
27537da2899SCharles.Forsyth			c.mode = tm.mode;
27637da2899SCharles.Forsyth			c.qid = nmf.qid;
27737da2899SCharles.Forsyth			nmf.nopen = 1;
27837da2899SCharles.Forsyth			srv.reply(ref Rmsg.Create(tm.tag, nmf.qid, Styx->MAXFDATA));
27937da2899SCharles.Forsyth		Read =>
28037da2899SCharles.Forsyth			(err, c, mf) := fidtomf(srv, qhash, tm.fid);
28137da2899SCharles.Forsyth			if (err == "" && !c.open)
28237da2899SCharles.Forsyth				err = Styxlib->Ebadfid;
28337da2899SCharles.Forsyth
28437da2899SCharles.Forsyth			if (err != "") {
28537da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
28637da2899SCharles.Forsyth				continue;
28737da2899SCharles.Forsyth			}
28837da2899SCharles.Forsyth			data: array of byte = nil;
28937da2899SCharles.Forsyth			if (mf.perm & Sys->DMDIR)
29037da2899SCharles.Forsyth				data = dirdata(mf, int tm.offset, tm.count);
29137da2899SCharles.Forsyth			else
29237da2899SCharles.Forsyth				data = filedata(mf, int tm.offset, tm.count);
29337da2899SCharles.Forsyth			mf.atime = now();
29437da2899SCharles.Forsyth			srv.reply(ref Rmsg.Read(tm.tag, data));
29537da2899SCharles.Forsyth		Write =>
29637da2899SCharles.Forsyth			(err, c, mf) := fidtomf(srv, qhash, tm.fid);
29737da2899SCharles.Forsyth			if (c != nil && !c.open)
29837da2899SCharles.Forsyth				err = Styxlib->Ebadfid;
29937da2899SCharles.Forsyth			if (err == nil && (mf.perm & Sys->DMDIR))
30037da2899SCharles.Forsyth				err = Styxlib->Eperm;
30137da2899SCharles.Forsyth			if (err == nil)
30237da2899SCharles.Forsyth				err = writefile(mf, int tm.offset, tm.data);
30337da2899SCharles.Forsyth			if (err != nil) {
30437da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
30537da2899SCharles.Forsyth				continue;
30637da2899SCharles.Forsyth			}
30737da2899SCharles.Forsyth			srv.reply(ref Rmsg.Write(tm.tag, len tm.data));
30837da2899SCharles.Forsyth		Clunk =>
30937da2899SCharles.Forsyth			(err, c, mf) := fidtomf(srv, qhash, tm.fid);
31037da2899SCharles.Forsyth			if (c != nil)
31137da2899SCharles.Forsyth				srv.chanfree(c);
31237da2899SCharles.Forsyth			if (err != nil) {
31337da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
31437da2899SCharles.Forsyth				continue;
31537da2899SCharles.Forsyth			}
31637da2899SCharles.Forsyth			if (c.open) {
31737da2899SCharles.Forsyth				if (c.mode & ORCLOSE)
31837da2899SCharles.Forsyth					unlink(mf);
31937da2899SCharles.Forsyth				mf.nopen--;
32037da2899SCharles.Forsyth				freeblks += delfile(qhash, mf);
32137da2899SCharles.Forsyth			}
32237da2899SCharles.Forsyth			srv.reply(ref Rmsg.Clunk(tm.tag));
32337da2899SCharles.Forsyth		Stat =>
324*3f1f06c5SCharles.Forsyth			(err, nil, mf) := fidtomf(srv, qhash, tm.fid);
32537da2899SCharles.Forsyth			if (err != nil) {
32637da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
32737da2899SCharles.Forsyth				continue;
32837da2899SCharles.Forsyth			}
32937da2899SCharles.Forsyth			srv.reply(ref Rmsg.Stat(tm.tag, fileinfo(mf)));
33037da2899SCharles.Forsyth		Remove =>
33137da2899SCharles.Forsyth			(err, c, mf) := fidtomf(srv, qhash, tm.fid);
33237da2899SCharles.Forsyth			if (err != nil) {
33337da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
33437da2899SCharles.Forsyth				continue;
33537da2899SCharles.Forsyth			}
33637da2899SCharles.Forsyth			srv.chanfree(c);
33737da2899SCharles.Forsyth			parent := mf.parent;
33837da2899SCharles.Forsyth			if (!modeok(OWRITE, parent.perm, c.uname, parent.owner))
33937da2899SCharles.Forsyth				err = Styxlib->Eperm;
34037da2899SCharles.Forsyth			if (err == "" && (mf.perm & Sys->DMDIR) && mf.kids != nil)
34137da2899SCharles.Forsyth				err = "directory not empty";
34237da2899SCharles.Forsyth			if (err == "" && mf == root)
34337da2899SCharles.Forsyth				err = "root directory";
34437da2899SCharles.Forsyth			if (err != nil) {
34537da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
34637da2899SCharles.Forsyth				continue;
34737da2899SCharles.Forsyth			}
34837da2899SCharles.Forsyth
34937da2899SCharles.Forsyth			unlink(mf);
35037da2899SCharles.Forsyth			if (c.open)
35137da2899SCharles.Forsyth				mf.nopen--;
35237da2899SCharles.Forsyth			freeblks += delfile(qhash, mf);
35337da2899SCharles.Forsyth			srv.reply(ref Rmsg.Remove(tm.tag));
35437da2899SCharles.Forsyth		Wstat =>
35537da2899SCharles.Forsyth			(err, c, mf) := fidtomf(srv, qhash, tm.fid);
35637da2899SCharles.Forsyth			stat := tm.stat;
357*3f1f06c5SCharles.Forsyth
35837da2899SCharles.Forsyth			if (err == nil && stat.name != mf.name) {
35937da2899SCharles.Forsyth				parent := mf.parent;
36037da2899SCharles.Forsyth				if (!modeok(OWRITE, parent.perm, c.uname, parent.owner))
36137da2899SCharles.Forsyth					err = Styxlib->Eperm;
36237da2899SCharles.Forsyth				else if (dirlookup(parent, stat.name) != nil)
36337da2899SCharles.Forsyth					err = Styxlib->Eexists;
36437da2899SCharles.Forsyth			}
36537da2899SCharles.Forsyth			if (err == nil && (stat.mode != mf.perm || stat.mtime != mf.mtime)) {
36637da2899SCharles.Forsyth				if (c.uname != mf.owner)
36737da2899SCharles.Forsyth					err = Styxlib->Eperm;
36837da2899SCharles.Forsyth			}
36937da2899SCharles.Forsyth			if (err != nil) {
37037da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, err));
37137da2899SCharles.Forsyth				continue;
37237da2899SCharles.Forsyth			}
37337da2899SCharles.Forsyth			isdir := mf.perm & Sys->DMDIR;
37437da2899SCharles.Forsyth			if(stat.name != nil)
37537da2899SCharles.Forsyth				mf.name = stat.name;
37637da2899SCharles.Forsyth			if(stat.mode != ~0)
37737da2899SCharles.Forsyth				mf.perm = stat.mode | isdir;
37837da2899SCharles.Forsyth			if(stat.mtime != ~0)
37937da2899SCharles.Forsyth				mf.mtime = stat.mtime;
38037da2899SCharles.Forsyth 			if(stat.uid != nil)
38137da2899SCharles.Forsyth 				mf.owner = stat.uid;
38237da2899SCharles.Forsyth			t := now();
38337da2899SCharles.Forsyth			mf.atime = t;
38437da2899SCharles.Forsyth			mf.parent.mtime = t;
38537da2899SCharles.Forsyth			# not supporting group id at the moment
38637da2899SCharles.Forsyth			srv.reply(ref Rmsg.Wstat(tm.tag));
38737da2899SCharles.Forsyth		Attach =>
38837da2899SCharles.Forsyth			c := srv.newchan(tm.fid);
38937da2899SCharles.Forsyth			if (c == nil) {
39037da2899SCharles.Forsyth				srv.reply(ref Rmsg.Error(tm.tag, Styxlib->Einuse));
39137da2899SCharles.Forsyth				continue;
39237da2899SCharles.Forsyth			}
39337da2899SCharles.Forsyth			c.uname = tm.uname;
39437da2899SCharles.Forsyth			c.qid = root.qid;
39537da2899SCharles.Forsyth			srv.reply(ref Rmsg.Attach(tm.tag, c.qid));
39637da2899SCharles.Forsyth		}
39737da2899SCharles.Forsyth	}
39837da2899SCharles.Forsyth}
39937da2899SCharles.Forsyth
40037da2899SCharles.Forsythwritefile(mf: ref Memfile, offset: int, data: array of byte): string
40137da2899SCharles.Forsyth{
40237da2899SCharles.Forsyth	if(mf.perm & Sys->DMAPPEND)
40337da2899SCharles.Forsyth		offset = mf.length;
40437da2899SCharles.Forsyth	startblk := offset/blksz;
40537da2899SCharles.Forsyth	nblks := ((len data + offset) - (startblk * blksz))/blksz;
40637da2899SCharles.Forsyth	lastblk := startblk + nblks;
40737da2899SCharles.Forsyth	need := lastblk + 1 - len mf.data;
40837da2899SCharles.Forsyth	if (need > 0) {
40937da2899SCharles.Forsyth		if (need > freeblks)
41037da2899SCharles.Forsyth			return Efull;
41137da2899SCharles.Forsyth		mf.data = (array [lastblk+1] of array of byte)[:] = mf.data;
41237da2899SCharles.Forsyth		freeblks -= need;
41337da2899SCharles.Forsyth	}
41437da2899SCharles.Forsyth	mf.length = max(mf.length, offset + len data);
41537da2899SCharles.Forsyth
41637da2899SCharles.Forsyth	# handle (possibly incomplete first block) separately
41737da2899SCharles.Forsyth	offset %= blksz;
41837da2899SCharles.Forsyth	end := min(blksz-offset, len data);
41937da2899SCharles.Forsyth	if (mf.data[startblk] == nil)
42037da2899SCharles.Forsyth		mf.data[startblk] = array [blksz] of byte;
42137da2899SCharles.Forsyth	mf.data[startblk++][offset:] = data[:end];
42237da2899SCharles.Forsyth
42337da2899SCharles.Forsyth	ix := blksz - offset;
42437da2899SCharles.Forsyth	while (ix < len data) {
42537da2899SCharles.Forsyth		if (mf.data[startblk] == nil)
42637da2899SCharles.Forsyth			mf.data[startblk] = array [blksz] of byte;
42737da2899SCharles.Forsyth		end = min(ix+blksz,len data);
42837da2899SCharles.Forsyth		mf.data[startblk++][:] = data[ix:end];
42937da2899SCharles.Forsyth		ix += blksz;
43037da2899SCharles.Forsyth	}
43137da2899SCharles.Forsyth	mf.mtime = now();
43237da2899SCharles.Forsyth	return nil;
43337da2899SCharles.Forsyth}
43437da2899SCharles.Forsyth
43537da2899SCharles.Forsythfiledata(mf: ref Memfile, offset, n: int): array of byte
43637da2899SCharles.Forsyth{
43737da2899SCharles.Forsyth	if (offset +n > mf.length)
43837da2899SCharles.Forsyth		n = mf.length - offset;
43937da2899SCharles.Forsyth	if (n == 0)
44037da2899SCharles.Forsyth		return nil;
44137da2899SCharles.Forsyth
44237da2899SCharles.Forsyth	data := array [n] of byte;
44337da2899SCharles.Forsyth	startblk := offset/blksz;
44437da2899SCharles.Forsyth	offset %= blksz;
44537da2899SCharles.Forsyth	rn := min(blksz - offset, n);
44637da2899SCharles.Forsyth	data[:] = mf.data[startblk++][offset:offset+rn];
44737da2899SCharles.Forsyth	ix := blksz - offset;
44837da2899SCharles.Forsyth	while (ix < n) {
44937da2899SCharles.Forsyth		rn = blksz;
45037da2899SCharles.Forsyth		if (ix+rn > n)
45137da2899SCharles.Forsyth			rn = n - ix;
45237da2899SCharles.Forsyth		data[ix:] = mf.data[startblk++][:rn];
45337da2899SCharles.Forsyth		ix += blksz;
45437da2899SCharles.Forsyth	}
45537da2899SCharles.Forsyth	return data;
45637da2899SCharles.Forsyth}
45737da2899SCharles.Forsyth
45837da2899SCharles.ForsythQHSIZE: con 256;
45937da2899SCharles.ForsythQHMASK: con QHSIZE-1;
46037da2899SCharles.Forsyth
46137da2899SCharles.ForsythQidhash.new() : ref Qidhash
46237da2899SCharles.Forsyth{
46337da2899SCharles.Forsyth	qh := ref Qidhash;
46437da2899SCharles.Forsyth	qh.buckets = array [QHSIZE] of ref Memfile;
46537da2899SCharles.Forsyth	qh.nextqid = 0;
46637da2899SCharles.Forsyth	return qh;
46737da2899SCharles.Forsyth}
46837da2899SCharles.Forsyth
46937da2899SCharles.ForsythQidhash.add(h : self ref Qidhash, mf : ref Memfile)
47037da2899SCharles.Forsyth{
47137da2899SCharles.Forsyth	path := h.nextqid++;
47237da2899SCharles.Forsyth	mf.qid = Sys->Qid(big path, 0, Sys->QTFILE);
47337da2899SCharles.Forsyth	bix := path & QHMASK;
47437da2899SCharles.Forsyth	mf.hashnext = h.buckets[bix];
47537da2899SCharles.Forsyth	h.buckets[bix] = mf;
47637da2899SCharles.Forsyth}
47737da2899SCharles.Forsyth
47837da2899SCharles.ForsythQidhash.remove(h : self ref Qidhash, mf : ref Memfile)
47937da2899SCharles.Forsyth{
48037da2899SCharles.Forsyth
48137da2899SCharles.Forsyth	bix := int mf.qid.path & QHMASK;
48237da2899SCharles.Forsyth	prev : ref Memfile;
48337da2899SCharles.Forsyth	for (cur := h.buckets[bix]; cur != nil; cur = cur.hashnext) {
48437da2899SCharles.Forsyth		if (cur == mf)
48537da2899SCharles.Forsyth			break;
48637da2899SCharles.Forsyth		prev = cur;
48737da2899SCharles.Forsyth	}
48837da2899SCharles.Forsyth	if (cur != nil) {
48937da2899SCharles.Forsyth		if (prev != nil)
49037da2899SCharles.Forsyth			prev.hashnext = cur.hashnext;
49137da2899SCharles.Forsyth		else
49237da2899SCharles.Forsyth			h.buckets[bix] = cur.hashnext;
49337da2899SCharles.Forsyth		cur.hashnext = nil;
49437da2899SCharles.Forsyth	}
49537da2899SCharles.Forsyth}
49637da2899SCharles.Forsyth
49737da2899SCharles.ForsythQidhash.lookup(h : self ref Qidhash, qid : Sys->Qid) : ref Memfile
49837da2899SCharles.Forsyth{
49937da2899SCharles.Forsyth	bix := int qid.path & QHMASK;
50037da2899SCharles.Forsyth	for (mf := h.buckets[bix]; mf != nil; mf = mf.hashnext)
50137da2899SCharles.Forsyth		if (mf.qid.path == qid.path)
50237da2899SCharles.Forsyth			break;
50337da2899SCharles.Forsyth	return mf;
50437da2899SCharles.Forsyth}
50537da2899SCharles.Forsyth
50637da2899SCharles.Forsythnewmf(qh : ref Qidhash, parent : ref Memfile, name, owner : string, perm : int) : ref Memfile
50737da2899SCharles.Forsyth{
50837da2899SCharles.Forsyth	# qid gets set by Qidhash.add()
50937da2899SCharles.Forsyth	t := now();
51037da2899SCharles.Forsyth	mf := ref Memfile (name, owner, Sys->Qid(big 0,0,Sys->QTFILE), perm, t, t, 0, nil, 0, parent, nil, nil, nil, nil);
51137da2899SCharles.Forsyth	qh.add(mf);
51237da2899SCharles.Forsyth	if(perm & Sys->DMDIR)
51337da2899SCharles.Forsyth		mf.qid.qtype = Sys->QTDIR;
51437da2899SCharles.Forsyth	return mf;
51537da2899SCharles.Forsyth}
51637da2899SCharles.Forsyth
51737da2899SCharles.Forsythfidtomf(srv : ref Styxserver, qh : ref Qidhash, fid : int) : (string, ref Styxlib->Chan, ref Memfile)
51837da2899SCharles.Forsyth{
51937da2899SCharles.Forsyth	c := srv.fidtochan(fid);
52037da2899SCharles.Forsyth	if (c == nil)
52137da2899SCharles.Forsyth		return (Styxlib->Ebadfid, nil, nil);
52237da2899SCharles.Forsyth	mf := qh.lookup(c.qid);
52337da2899SCharles.Forsyth	if (mf == nil)
52437da2899SCharles.Forsyth		return (Styxlib->Enotfound, c, nil);
52537da2899SCharles.Forsyth	return (nil, c, mf);
52637da2899SCharles.Forsyth}
52737da2899SCharles.Forsyth
52837da2899SCharles.Forsythunlink(mf : ref Memfile)
52937da2899SCharles.Forsyth{
53037da2899SCharles.Forsyth	parent := mf.parent;
53137da2899SCharles.Forsyth	if (parent == nil)
53237da2899SCharles.Forsyth		return;
53337da2899SCharles.Forsyth	if (mf.next != nil)
53437da2899SCharles.Forsyth		mf.next.prev = mf.prev;
53537da2899SCharles.Forsyth	if (mf.prev != nil)
53637da2899SCharles.Forsyth		mf.prev.next = mf.next;
53737da2899SCharles.Forsyth	else
53837da2899SCharles.Forsyth		mf.parent.kids = mf.next;
53937da2899SCharles.Forsyth	mf.parent = nil;
54037da2899SCharles.Forsyth	mf.prev = nil;
54137da2899SCharles.Forsyth	mf.next = nil;
54237da2899SCharles.Forsyth}
54337da2899SCharles.Forsyth
54437da2899SCharles.Forsythdelfile(qh : ref Qidhash, mf : ref Memfile) : int
54537da2899SCharles.Forsyth{
54637da2899SCharles.Forsyth	if (mf.nopen <= 0 && mf.parent == nil && mf.kids == nil
54737da2899SCharles.Forsyth	&& mf.prev == nil && mf.next == nil) {
54837da2899SCharles.Forsyth		qh.remove(mf);
54937da2899SCharles.Forsyth		nblks := len mf.data;
55037da2899SCharles.Forsyth		mf.data = nil;
55137da2899SCharles.Forsyth		return nblks;
55237da2899SCharles.Forsyth	}
55337da2899SCharles.Forsyth	return 0;
55437da2899SCharles.Forsyth}
55537da2899SCharles.Forsyth
55637da2899SCharles.Forsythdirlookup(dir : ref Memfile, name : string) : ref Memfile
55737da2899SCharles.Forsyth{
55837da2899SCharles.Forsyth	if (name == ".")
55937da2899SCharles.Forsyth		return dir;
56037da2899SCharles.Forsyth	if (name == "..")
56137da2899SCharles.Forsyth		return dir.parent;
56237da2899SCharles.Forsyth	for (mf := dir.kids; mf != nil; mf = mf.next) {
56337da2899SCharles.Forsyth		if (mf.name == name)
56437da2899SCharles.Forsyth			break;
56537da2899SCharles.Forsyth	}
56637da2899SCharles.Forsyth	return mf;
56737da2899SCharles.Forsyth}
56837da2899SCharles.Forsyth
56937da2899SCharles.Forsythaccess := array[] of {8r400, 8r200, 8r600, 8r100};
57037da2899SCharles.Forsythmodeok(mode, perm : int, user, owner : string) : int
57137da2899SCharles.Forsyth{
57237da2899SCharles.Forsyth	if(mode >= (OTRUNC|ORCLOSE|OREAD|OWRITE))
57337da2899SCharles.Forsyth		return 0;
57437da2899SCharles.Forsyth
57537da2899SCharles.Forsyth	# not handling groups!
57637da2899SCharles.Forsyth	if (user != owner)
57737da2899SCharles.Forsyth		perm <<= 6;
57837da2899SCharles.Forsyth
57937da2899SCharles.Forsyth	if ((mode & OTRUNC) && !(perm & 8r200))
58037da2899SCharles.Forsyth		return 0;
58137da2899SCharles.Forsyth
58237da2899SCharles.Forsyth	a := access[mode &3];
58337da2899SCharles.Forsyth	if ((a & perm) != a)
58437da2899SCharles.Forsyth		return 0;
58537da2899SCharles.Forsyth	return 1;
58637da2899SCharles.Forsyth}
58737da2899SCharles.Forsyth
58837da2899SCharles.Forsythdirdata(dir : ref Memfile, start, n : int) : array of byte
58937da2899SCharles.Forsyth{
59037da2899SCharles.Forsyth	data := array[Styx->MAXFDATA] of byte;
59137da2899SCharles.Forsyth	for (k := dir.kids; start > 0 && k != nil; k = k.next) {
59237da2899SCharles.Forsyth		a := styx->packdir(fileinfo(k));
59337da2899SCharles.Forsyth		start -= len a;
59437da2899SCharles.Forsyth	}
59537da2899SCharles.Forsyth	r := 0;
59637da2899SCharles.Forsyth	for (; r < n && k != nil; k = k.next) {
59737da2899SCharles.Forsyth		a := styx->packdir(fileinfo(k));
59837da2899SCharles.Forsyth		if(r+len a > n)
59937da2899SCharles.Forsyth			break;
60037da2899SCharles.Forsyth		data[r:] = a;
60137da2899SCharles.Forsyth		r += len a;
60237da2899SCharles.Forsyth	}
60337da2899SCharles.Forsyth	return data[0:r];
60437da2899SCharles.Forsyth}
60537da2899SCharles.Forsyth
60637da2899SCharles.Forsythfileinfo(f : ref Memfile) : Sys->Dir
60737da2899SCharles.Forsyth{
60837da2899SCharles.Forsyth	dir := sys->zerodir;
60937da2899SCharles.Forsyth	dir.name = f.name;
61037da2899SCharles.Forsyth	dir.uid = f.owner;
61137da2899SCharles.Forsyth	dir.gid = "memfs";
61237da2899SCharles.Forsyth	dir.qid = f.qid;
61337da2899SCharles.Forsyth	dir.mode = f.perm;
61437da2899SCharles.Forsyth	dir.atime = f.atime;
61537da2899SCharles.Forsyth	dir.mtime = f.mtime;
61637da2899SCharles.Forsyth	dir.length = big f.length;
61737da2899SCharles.Forsyth	dir.dtype = 0;
61837da2899SCharles.Forsyth	dir.dev = 0;
61937da2899SCharles.Forsyth	return dir;
62037da2899SCharles.Forsyth}
62137da2899SCharles.Forsyth
62237da2899SCharles.Forsythmin(a, b : int) : int
62337da2899SCharles.Forsyth{
62437da2899SCharles.Forsyth	if (a < b)
62537da2899SCharles.Forsyth		return a;
62637da2899SCharles.Forsyth	return b;
62737da2899SCharles.Forsyth}
62837da2899SCharles.Forsyth
62937da2899SCharles.Forsythmax(a, b : int) : int
63037da2899SCharles.Forsyth{
63137da2899SCharles.Forsyth	if (a > b)
63237da2899SCharles.Forsyth		return a;
63337da2899SCharles.Forsyth	return b;
63437da2899SCharles.Forsyth}
63537da2899SCharles.Forsyth
63637da2899SCharles.Forsythnow(): int
63737da2899SCharles.Forsyth{
63837da2899SCharles.Forsyth	if (timefd == nil)
63937da2899SCharles.Forsyth		return 0;
64037da2899SCharles.Forsyth	buf := array[128] of byte;
64137da2899SCharles.Forsyth	sys->seek(timefd, big 0, 0);
64237da2899SCharles.Forsyth	n := sys->read(timefd, buf, len buf);
64337da2899SCharles.Forsyth	if(n < 0)
64437da2899SCharles.Forsyth		return 0;
64537da2899SCharles.Forsyth
64637da2899SCharles.Forsyth	t := (big string buf[0:n]) / big 1000000;
64737da2899SCharles.Forsyth	return int t;
64837da2899SCharles.Forsyth}
649