xref: /plan9/sys/lib/dist/cmd/bzfs/oramfs.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include <u.h>
2*9a747e4fSDavid du Colombier #include <libc.h>
3*9a747e4fSDavid du Colombier #include <auth.h>
4*9a747e4fSDavid du Colombier #include <fcall.h>
5*9a747e4fSDavid du Colombier #include "bzfs.h"
6*9a747e4fSDavid du Colombier 
7*9a747e4fSDavid du Colombier /*
8*9a747e4fSDavid du Colombier  * Rather than reading /adm/users, which is a lot of work for
9*9a747e4fSDavid du Colombier  * a toy program, we assume all groups have the form
10*9a747e4fSDavid du Colombier  *	NNN:user:user:
11*9a747e4fSDavid du Colombier  * meaning that each user is the leader of his own group.
12*9a747e4fSDavid du Colombier  */
13*9a747e4fSDavid du Colombier 
14*9a747e4fSDavid du Colombier enum
15*9a747e4fSDavid du Colombier {
16*9a747e4fSDavid du Colombier 	OPERM	= 0x3,		/* mask of all permission types in open mode */
17*9a747e4fSDavid du Colombier 	Nram	= 512,
18*9a747e4fSDavid du Colombier 	Maxsize	= 512*1024*1024,
19*9a747e4fSDavid du Colombier 	Maxfdata	= 8192,
20*9a747e4fSDavid du Colombier };
21*9a747e4fSDavid du Colombier 
22*9a747e4fSDavid du Colombier typedef struct Fid Fid;
23*9a747e4fSDavid du Colombier typedef struct Ram Ram;
24*9a747e4fSDavid du Colombier 
25*9a747e4fSDavid du Colombier struct Fid
26*9a747e4fSDavid du Colombier {
27*9a747e4fSDavid du Colombier 	short	busy;
28*9a747e4fSDavid du Colombier 	short	open;
29*9a747e4fSDavid du Colombier 	short	rclose;
30*9a747e4fSDavid du Colombier 	int	fid;
31*9a747e4fSDavid du Colombier 	Fid	*next;
32*9a747e4fSDavid du Colombier 	char	*user;
33*9a747e4fSDavid du Colombier 	Ram	*ram;
34*9a747e4fSDavid du Colombier };
35*9a747e4fSDavid du Colombier 
36*9a747e4fSDavid du Colombier struct Ram
37*9a747e4fSDavid du Colombier {
38*9a747e4fSDavid du Colombier 	short	busy;
39*9a747e4fSDavid du Colombier 	short	open;
40*9a747e4fSDavid du Colombier 	long	parent;		/* index in Ram array */
41*9a747e4fSDavid du Colombier 	Qid	qid;
42*9a747e4fSDavid du Colombier 	long	perm;
43*9a747e4fSDavid du Colombier 	char	*name;
44*9a747e4fSDavid du Colombier 	ulong	atime;
45*9a747e4fSDavid du Colombier 	ulong	mtime;
46*9a747e4fSDavid du Colombier 	char	*user;
47*9a747e4fSDavid du Colombier 	char	*group;
48*9a747e4fSDavid du Colombier 	char	*muid;
49*9a747e4fSDavid du Colombier 	char	*data;
50*9a747e4fSDavid du Colombier 	long	ndata;
51*9a747e4fSDavid du Colombier };
52*9a747e4fSDavid du Colombier 
53*9a747e4fSDavid du Colombier enum
54*9a747e4fSDavid du Colombier {
55*9a747e4fSDavid du Colombier 	Pexec =		1,
56*9a747e4fSDavid du Colombier 	Pwrite = 	2,
57*9a747e4fSDavid du Colombier 	Pread = 	4,
58*9a747e4fSDavid du Colombier 	Pother = 	1,
59*9a747e4fSDavid du Colombier 	Pgroup = 	8,
60*9a747e4fSDavid du Colombier 	Powner =	64,
61*9a747e4fSDavid du Colombier };
62*9a747e4fSDavid du Colombier 
63*9a747e4fSDavid du Colombier ulong	path;		/* incremented for each new file */
64*9a747e4fSDavid du Colombier Fid	*fids;
65*9a747e4fSDavid du Colombier Ram	ram[Nram];
66*9a747e4fSDavid du Colombier int	nram;
67*9a747e4fSDavid du Colombier int	mfd[2];
68*9a747e4fSDavid du Colombier char	*user;
69*9a747e4fSDavid du Colombier uchar	mdata[IOHDRSZ+Maxfdata];
70*9a747e4fSDavid du Colombier uchar	rdata[Maxfdata];	/* buffer for data in reply */
71*9a747e4fSDavid du Colombier uchar statbuf[STATMAX];
72*9a747e4fSDavid du Colombier Fcall thdr;
73*9a747e4fSDavid du Colombier Fcall	rhdr;
74*9a747e4fSDavid du Colombier int	messagesize = sizeof mdata;
75*9a747e4fSDavid du Colombier 
76*9a747e4fSDavid du Colombier Fid *	newfid(int);
77*9a747e4fSDavid du Colombier uint	ramstat(Ram*, uchar*, uint);
78*9a747e4fSDavid du Colombier void	io(void);
79*9a747e4fSDavid du Colombier void	*erealloc(void*, ulong);
80*9a747e4fSDavid du Colombier void	*emalloc(ulong);
81*9a747e4fSDavid du Colombier char	*estrdup(char*);
82*9a747e4fSDavid du Colombier void	ramfsusage(void);
83*9a747e4fSDavid du Colombier int	perm(Fid*, Ram*, int);
84*9a747e4fSDavid du Colombier char *atom(char*);
85*9a747e4fSDavid du Colombier 
86*9a747e4fSDavid du Colombier char	*rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
87*9a747e4fSDavid du Colombier 	*rattach(Fid*), *rwalk(Fid*),
88*9a747e4fSDavid du Colombier 	*ropen(Fid*), *rcreate(Fid*),
89*9a747e4fSDavid du Colombier 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
90*9a747e4fSDavid du Colombier 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
91*9a747e4fSDavid du Colombier 
92*9a747e4fSDavid du Colombier char 	*(*fcalls[])(Fid*) = {
93*9a747e4fSDavid du Colombier 	[Tversion]	rversion,
94*9a747e4fSDavid du Colombier 	[Tflush]	rflush,
95*9a747e4fSDavid du Colombier 	[Tauth]	rauth,
96*9a747e4fSDavid du Colombier 	[Tattach]	rattach,
97*9a747e4fSDavid du Colombier 	[Twalk]		rwalk,
98*9a747e4fSDavid du Colombier 	[Topen]		ropen,
99*9a747e4fSDavid du Colombier 	[Tcreate]	rcreate,
100*9a747e4fSDavid du Colombier 	[Tread]		rread,
101*9a747e4fSDavid du Colombier 	[Twrite]	rwrite,
102*9a747e4fSDavid du Colombier 	[Tclunk]	rclunk,
103*9a747e4fSDavid du Colombier 	[Tremove]	rremove,
104*9a747e4fSDavid du Colombier 	[Tstat]		rstat,
105*9a747e4fSDavid du Colombier 	[Twstat]	rwstat,
106*9a747e4fSDavid du Colombier };
107*9a747e4fSDavid du Colombier 
108*9a747e4fSDavid du Colombier char	Eperm[] =	"permission denied";
109*9a747e4fSDavid du Colombier char	Enotdir[] =	"not a directory";
110*9a747e4fSDavid du Colombier char	Enoauth[] =	"no authentication in ramfs";
111*9a747e4fSDavid du Colombier char	Enotexist[] =	"file does not exist";
112*9a747e4fSDavid du Colombier char	Einuse[] =	"file in use";
113*9a747e4fSDavid du Colombier char	Eexist[] =	"file exists";
114*9a747e4fSDavid du Colombier char	Eisdir[] =	"file is a directory";
115*9a747e4fSDavid du Colombier char	Enotowner[] =	"not owner";
116*9a747e4fSDavid du Colombier char	Eisopen[] = 	"file already open for I/O";
117*9a747e4fSDavid du Colombier char	Excl[] = 	"exclusive use file already open";
118*9a747e4fSDavid du Colombier char	Ename[] = 	"illegal name";
119*9a747e4fSDavid du Colombier char	Eversion[] =	"unknown 9P version";
120*9a747e4fSDavid du Colombier 
121*9a747e4fSDavid du Colombier int debug;
122*9a747e4fSDavid du Colombier 
123*9a747e4fSDavid du Colombier void
notifyf(void * a,char * s)124*9a747e4fSDavid du Colombier notifyf(void *a, char *s)
125*9a747e4fSDavid du Colombier {
126*9a747e4fSDavid du Colombier 	USED(a);
127*9a747e4fSDavid du Colombier 	if(strncmp(s, "interrupt", 9) == 0)
128*9a747e4fSDavid du Colombier 		noted(NCONT);
129*9a747e4fSDavid du Colombier 	noted(NDFLT);
130*9a747e4fSDavid du Colombier }
131*9a747e4fSDavid du Colombier 
132*9a747e4fSDavid du Colombier void
ramfsmain(int argc,char * argv[])133*9a747e4fSDavid du Colombier ramfsmain(int argc, char *argv[])
134*9a747e4fSDavid du Colombier {
135*9a747e4fSDavid du Colombier 	Ram *r;
136*9a747e4fSDavid du Colombier 	char *defmnt;
137*9a747e4fSDavid du Colombier 	int p[2];
138*9a747e4fSDavid du Colombier 	char buf[32];
139*9a747e4fSDavid du Colombier 	int fd, srvfd;
140*9a747e4fSDavid du Colombier 	int stdio = 0;
141*9a747e4fSDavid du Colombier 
142*9a747e4fSDavid du Colombier 	srvfd = -1;
143*9a747e4fSDavid du Colombier 	defmnt = "/tmp";
144*9a747e4fSDavid du Colombier 	ARGBEGIN{
145*9a747e4fSDavid du Colombier 	case 'D':
146*9a747e4fSDavid du Colombier 		debug = 1;
147*9a747e4fSDavid du Colombier 		break;
148*9a747e4fSDavid du Colombier 	case 'i':		/* this is DIFFERENT from normal ramfs; use 1 for both for kernel */
149*9a747e4fSDavid du Colombier 		defmnt = 0;
150*9a747e4fSDavid du Colombier 		stdio = 1;
151*9a747e4fSDavid du Colombier 		srvfd = 0;
152*9a747e4fSDavid du Colombier 		mfd[0] = 1;
153*9a747e4fSDavid du Colombier 		mfd[1] = 1;
154*9a747e4fSDavid du Colombier 		break;
155*9a747e4fSDavid du Colombier 	case 's':
156*9a747e4fSDavid du Colombier 		defmnt = 0;
157*9a747e4fSDavid du Colombier 		break;
158*9a747e4fSDavid du Colombier 	case 'm':
159*9a747e4fSDavid du Colombier 		defmnt = ARGF();
160*9a747e4fSDavid du Colombier 		break;
161*9a747e4fSDavid du Colombier 	default:
162*9a747e4fSDavid du Colombier 		ramfsusage();
163*9a747e4fSDavid du Colombier 	}ARGEND
164*9a747e4fSDavid du Colombier 
165*9a747e4fSDavid du Colombier 	if(!stdio){
166*9a747e4fSDavid du Colombier 		if(pipe(p) < 0)
167*9a747e4fSDavid du Colombier 			error("pipe failed");
168*9a747e4fSDavid du Colombier 		srvfd = p[1];
169*9a747e4fSDavid du Colombier 		mfd[0] = p[0];
170*9a747e4fSDavid du Colombier 		mfd[1] = p[0];
171*9a747e4fSDavid du Colombier 		if(defmnt == 0){
172*9a747e4fSDavid du Colombier 			fd = create("#s/ramfs", OWRITE, 0666);
173*9a747e4fSDavid du Colombier 			if(fd < 0)
174*9a747e4fSDavid du Colombier 				error("create of /srv/ramfs failed");
175*9a747e4fSDavid du Colombier 			sprint(buf, "%d", p[1]);
176*9a747e4fSDavid du Colombier 			if(write(fd, buf, strlen(buf)) < 0)
177*9a747e4fSDavid du Colombier 				error("writing /srv/ramfs");
178*9a747e4fSDavid du Colombier 		}
179*9a747e4fSDavid du Colombier 	}
180*9a747e4fSDavid du Colombier 
181*9a747e4fSDavid du Colombier 	user = atom(getuser());
182*9a747e4fSDavid du Colombier 	notify(notifyf);
183*9a747e4fSDavid du Colombier 	nram = 1;
184*9a747e4fSDavid du Colombier 	r = &ram[0];
185*9a747e4fSDavid du Colombier 	r->busy = 1;
186*9a747e4fSDavid du Colombier 	r->data = 0;
187*9a747e4fSDavid du Colombier 	r->ndata = 0;
188*9a747e4fSDavid du Colombier 	r->perm = DMDIR | 0775;
189*9a747e4fSDavid du Colombier 	r->qid.type = QTDIR;
190*9a747e4fSDavid du Colombier 	r->qid.path = 0LL;
191*9a747e4fSDavid du Colombier 	r->qid.vers = 0;
192*9a747e4fSDavid du Colombier 	r->parent = 0;
193*9a747e4fSDavid du Colombier 	r->user = user;
194*9a747e4fSDavid du Colombier 	r->group = user;
195*9a747e4fSDavid du Colombier 	r->muid = user;
196*9a747e4fSDavid du Colombier 	r->atime = time(0);
197*9a747e4fSDavid du Colombier 	r->mtime = r->atime;
198*9a747e4fSDavid du Colombier 	r->name = estrdup(".");
199*9a747e4fSDavid du Colombier 
200*9a747e4fSDavid du Colombier 	if(debug)
201*9a747e4fSDavid du Colombier 		fmtinstall('F', fcallfmt);
202*9a747e4fSDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
203*9a747e4fSDavid du Colombier 	case -1:
204*9a747e4fSDavid du Colombier 		error("fork");
205*9a747e4fSDavid du Colombier 	case 0:
206*9a747e4fSDavid du Colombier 		close(srvfd);
207*9a747e4fSDavid du Colombier 		io();
208*9a747e4fSDavid du Colombier 		break;
209*9a747e4fSDavid du Colombier 	default:
210*9a747e4fSDavid du Colombier 		close(mfd[0]);	/* don't deadlock if child fails */
211*9a747e4fSDavid du Colombier 		if(defmnt && mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
212*9a747e4fSDavid du Colombier 			error("mount failed: %r");
213*9a747e4fSDavid du Colombier 	}
214*9a747e4fSDavid du Colombier }
215*9a747e4fSDavid du Colombier 
216*9a747e4fSDavid du Colombier char*
rversion(Fid *)217*9a747e4fSDavid du Colombier rversion(Fid*)
218*9a747e4fSDavid du Colombier {
219*9a747e4fSDavid du Colombier 	Fid *f;
220*9a747e4fSDavid du Colombier 
221*9a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next)
222*9a747e4fSDavid du Colombier 		if(f->busy)
223*9a747e4fSDavid du Colombier 			rclunk(f);
224*9a747e4fSDavid du Colombier 	if(thdr.msize > sizeof mdata)
225*9a747e4fSDavid du Colombier 		rhdr.msize = sizeof mdata;
226*9a747e4fSDavid du Colombier 	else
227*9a747e4fSDavid du Colombier 		rhdr.msize = thdr.msize;
228*9a747e4fSDavid du Colombier 	messagesize = rhdr.msize;
229*9a747e4fSDavid du Colombier 	if(strncmp(thdr.version, "9P2000", 6) != 0)
230*9a747e4fSDavid du Colombier 		return Eversion;
231*9a747e4fSDavid du Colombier 	rhdr.version = "9P2000";
232*9a747e4fSDavid du Colombier 	return 0;
233*9a747e4fSDavid du Colombier }
234*9a747e4fSDavid du Colombier 
235*9a747e4fSDavid du Colombier char*
rauth(Fid *)236*9a747e4fSDavid du Colombier rauth(Fid*)
237*9a747e4fSDavid du Colombier {
238*9a747e4fSDavid du Colombier 	return "ramfs: no authentication required";
239*9a747e4fSDavid du Colombier }
240*9a747e4fSDavid du Colombier 
241*9a747e4fSDavid du Colombier char*
rflush(Fid * f)242*9a747e4fSDavid du Colombier rflush(Fid *f)
243*9a747e4fSDavid du Colombier {
244*9a747e4fSDavid du Colombier 	USED(f);
245*9a747e4fSDavid du Colombier 	return 0;
246*9a747e4fSDavid du Colombier }
247*9a747e4fSDavid du Colombier 
248*9a747e4fSDavid du Colombier char*
rattach(Fid * f)249*9a747e4fSDavid du Colombier rattach(Fid *f)
250*9a747e4fSDavid du Colombier {
251*9a747e4fSDavid du Colombier 	/* no authentication! */
252*9a747e4fSDavid du Colombier 	f->busy = 1;
253*9a747e4fSDavid du Colombier 	f->rclose = 0;
254*9a747e4fSDavid du Colombier 	f->ram = &ram[0];
255*9a747e4fSDavid du Colombier 	rhdr.qid = f->ram->qid;
256*9a747e4fSDavid du Colombier 	if(thdr.uname[0])
257*9a747e4fSDavid du Colombier 		f->user = atom(thdr.uname);
258*9a747e4fSDavid du Colombier 	else
259*9a747e4fSDavid du Colombier 		f->user = atom("none");
260*9a747e4fSDavid du Colombier 	if(strcmp(user, "none") == 0)
261*9a747e4fSDavid du Colombier 		user = f->user;
262*9a747e4fSDavid du Colombier 	return 0;
263*9a747e4fSDavid du Colombier }
264*9a747e4fSDavid du Colombier 
265*9a747e4fSDavid du Colombier char*
clone(Fid * f,Fid ** nf)266*9a747e4fSDavid du Colombier clone(Fid *f, Fid **nf)
267*9a747e4fSDavid du Colombier {
268*9a747e4fSDavid du Colombier 	if(f->open)
269*9a747e4fSDavid du Colombier 		return Eisopen;
270*9a747e4fSDavid du Colombier 	if(f->ram->busy == 0)
271*9a747e4fSDavid du Colombier 		return Enotexist;
272*9a747e4fSDavid du Colombier 	*nf = newfid(thdr.newfid);
273*9a747e4fSDavid du Colombier 	(*nf)->busy = 1;
274*9a747e4fSDavid du Colombier 	(*nf)->open = 0;
275*9a747e4fSDavid du Colombier 	(*nf)->rclose = 0;
276*9a747e4fSDavid du Colombier 	(*nf)->ram = f->ram;
277*9a747e4fSDavid du Colombier 	(*nf)->user = f->user;	/* no ref count; the leakage is minor */
278*9a747e4fSDavid du Colombier 	return 0;
279*9a747e4fSDavid du Colombier }
280*9a747e4fSDavid du Colombier 
281*9a747e4fSDavid du Colombier char*
rwalk(Fid * f)282*9a747e4fSDavid du Colombier rwalk(Fid *f)
283*9a747e4fSDavid du Colombier {
284*9a747e4fSDavid du Colombier 	Ram *r, *fram;
285*9a747e4fSDavid du Colombier 	char *name;
286*9a747e4fSDavid du Colombier 	Ram *parent;
287*9a747e4fSDavid du Colombier 	Fid *nf;
288*9a747e4fSDavid du Colombier 	char *err;
289*9a747e4fSDavid du Colombier 	ulong t;
290*9a747e4fSDavid du Colombier 	int i;
291*9a747e4fSDavid du Colombier 
292*9a747e4fSDavid du Colombier 	err = nil;
293*9a747e4fSDavid du Colombier 	nf = nil;
294*9a747e4fSDavid du Colombier 	rhdr.nwqid = 0;
295*9a747e4fSDavid du Colombier 	if(rhdr.newfid != rhdr.fid){
296*9a747e4fSDavid du Colombier 		err = clone(f, &nf);
297*9a747e4fSDavid du Colombier 		if(err)
298*9a747e4fSDavid du Colombier 			return err;
299*9a747e4fSDavid du Colombier 		f = nf;	/* walk the new fid */
300*9a747e4fSDavid du Colombier 	}
301*9a747e4fSDavid du Colombier 	fram = f->ram;
302*9a747e4fSDavid du Colombier 	if(thdr.nwname > 0){
303*9a747e4fSDavid du Colombier 		t = time(0);
304*9a747e4fSDavid du Colombier 		for(i=0; i<thdr.nwname && i<MAXWELEM; i++){
305*9a747e4fSDavid du Colombier 			if((fram->qid.type & QTDIR) == 0){
306*9a747e4fSDavid du Colombier 				err = Enotdir;
307*9a747e4fSDavid du Colombier  				break;
308*9a747e4fSDavid du Colombier 			}
309*9a747e4fSDavid du Colombier 			if(fram->busy == 0){
310*9a747e4fSDavid du Colombier 				err = Enotexist;
311*9a747e4fSDavid du Colombier 				break;
312*9a747e4fSDavid du Colombier 			}
313*9a747e4fSDavid du Colombier 			fram->atime = t;
314*9a747e4fSDavid du Colombier 			name = thdr.wname[i];
315*9a747e4fSDavid du Colombier 			if(strcmp(name, ".") == 0){
316*9a747e4fSDavid du Colombier     Found:
317*9a747e4fSDavid du Colombier 				rhdr.nwqid++;
318*9a747e4fSDavid du Colombier 				rhdr.wqid[i] = fram->qid;
319*9a747e4fSDavid du Colombier 				continue;
320*9a747e4fSDavid du Colombier 			}
321*9a747e4fSDavid du Colombier 			parent = &ram[fram->parent];
322*9a747e4fSDavid du Colombier #ifdef CHECKS
323*9a747e4fSDavid du Colombier 			if(!perm(f, parent, Pexec)){
324*9a747e4fSDavid du Colombier 				err = Eperm;
325*9a747e4fSDavid du Colombier 				break;
326*9a747e4fSDavid du Colombier 			}
327*9a747e4fSDavid du Colombier #endif
328*9a747e4fSDavid du Colombier 			if(strcmp(name, "..") == 0){
329*9a747e4fSDavid du Colombier 				fram = parent;
330*9a747e4fSDavid du Colombier 				goto Found;
331*9a747e4fSDavid du Colombier 			}
332*9a747e4fSDavid du Colombier 			for(r=ram; r < &ram[nram]; r++)
333*9a747e4fSDavid du Colombier 				if(r->busy && r->parent==fram-ram && strcmp(name, r->name)==0){
334*9a747e4fSDavid du Colombier 					fram = r;
335*9a747e4fSDavid du Colombier 					goto Found;
336*9a747e4fSDavid du Colombier 				}
337*9a747e4fSDavid du Colombier 			break;
338*9a747e4fSDavid du Colombier 		}
339*9a747e4fSDavid du Colombier 		if(i==0 && err == nil)
340*9a747e4fSDavid du Colombier 			err = Enotexist;
341*9a747e4fSDavid du Colombier 	}
342*9a747e4fSDavid du Colombier 	if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){
343*9a747e4fSDavid du Colombier 		/* clunk the new fid, which is the one we walked */
344*9a747e4fSDavid du Colombier 		f->busy = 0;
345*9a747e4fSDavid du Colombier 		f->ram = nil;
346*9a747e4fSDavid du Colombier 	}
347*9a747e4fSDavid du Colombier 	if(rhdr.nwqid == thdr.nwname)	/* update the fid after a successful walk */
348*9a747e4fSDavid du Colombier 		f->ram = fram;
349*9a747e4fSDavid du Colombier 	return err;
350*9a747e4fSDavid du Colombier }
351*9a747e4fSDavid du Colombier 
352*9a747e4fSDavid du Colombier char *
ropen(Fid * f)353*9a747e4fSDavid du Colombier ropen(Fid *f)
354*9a747e4fSDavid du Colombier {
355*9a747e4fSDavid du Colombier 	Ram *r;
356*9a747e4fSDavid du Colombier 	int mode, trunc;
357*9a747e4fSDavid du Colombier 
358*9a747e4fSDavid du Colombier 	if(f->open)
359*9a747e4fSDavid du Colombier 		return Eisopen;
360*9a747e4fSDavid du Colombier 	r = f->ram;
361*9a747e4fSDavid du Colombier 	if(r->busy == 0)
362*9a747e4fSDavid du Colombier 		return Enotexist;
363*9a747e4fSDavid du Colombier 	if(r->perm & DMEXCL)
364*9a747e4fSDavid du Colombier 		if(r->open)
365*9a747e4fSDavid du Colombier 			return Excl;
366*9a747e4fSDavid du Colombier 	mode = thdr.mode;
367*9a747e4fSDavid du Colombier 	if(r->qid.type & QTDIR){
368*9a747e4fSDavid du Colombier 		if(mode != OREAD)
369*9a747e4fSDavid du Colombier 			return Eperm;
370*9a747e4fSDavid du Colombier 		rhdr.qid = r->qid;
371*9a747e4fSDavid du Colombier 		return 0;
372*9a747e4fSDavid du Colombier 	}
373*9a747e4fSDavid du Colombier 	if(mode & ORCLOSE){
374*9a747e4fSDavid du Colombier 		/* can't remove root; must be able to write parent */
375*9a747e4fSDavid du Colombier 		if(r->qid.path==0 || !perm(f, &ram[r->parent], Pwrite))
376*9a747e4fSDavid du Colombier 			return Eperm;
377*9a747e4fSDavid du Colombier 		f->rclose = 1;
378*9a747e4fSDavid du Colombier 	}
379*9a747e4fSDavid du Colombier 	trunc = mode & OTRUNC;
380*9a747e4fSDavid du Colombier 	mode &= OPERM;
381*9a747e4fSDavid du Colombier 	if(mode==OWRITE || mode==ORDWR || trunc)
382*9a747e4fSDavid du Colombier 		if(!perm(f, r, Pwrite))
383*9a747e4fSDavid du Colombier 			return Eperm;
384*9a747e4fSDavid du Colombier 	if(mode==OREAD || mode==ORDWR)
385*9a747e4fSDavid du Colombier 		if(!perm(f, r, Pread))
386*9a747e4fSDavid du Colombier 			return Eperm;
387*9a747e4fSDavid du Colombier 	if(mode==OEXEC)
388*9a747e4fSDavid du Colombier 		if(!perm(f, r, Pexec))
389*9a747e4fSDavid du Colombier 			return Eperm;
390*9a747e4fSDavid du Colombier 	if(trunc && (r->perm&DMAPPEND)==0){
391*9a747e4fSDavid du Colombier 		r->ndata = 0;
392*9a747e4fSDavid du Colombier 		if(r->data)
393*9a747e4fSDavid du Colombier 			free(r->data);
394*9a747e4fSDavid du Colombier 		r->data = 0;
395*9a747e4fSDavid du Colombier 		r->qid.vers++;
396*9a747e4fSDavid du Colombier 	}
397*9a747e4fSDavid du Colombier 	rhdr.qid = r->qid;
398*9a747e4fSDavid du Colombier 	rhdr.iounit = messagesize-IOHDRSZ;
399*9a747e4fSDavid du Colombier 	f->open = 1;
400*9a747e4fSDavid du Colombier 	r->open++;
401*9a747e4fSDavid du Colombier 	return 0;
402*9a747e4fSDavid du Colombier }
403*9a747e4fSDavid du Colombier 
404*9a747e4fSDavid du Colombier char *
rcreate(Fid * f)405*9a747e4fSDavid du Colombier rcreate(Fid *f)
406*9a747e4fSDavid du Colombier {
407*9a747e4fSDavid du Colombier 	Ram *r;
408*9a747e4fSDavid du Colombier 	char *name;
409*9a747e4fSDavid du Colombier 	long parent, prm;
410*9a747e4fSDavid du Colombier 
411*9a747e4fSDavid du Colombier 	if(f->open)
412*9a747e4fSDavid du Colombier 		return Eisopen;
413*9a747e4fSDavid du Colombier 	if(f->ram->busy == 0)
414*9a747e4fSDavid du Colombier 		return Enotexist;
415*9a747e4fSDavid du Colombier 	parent = f->ram - ram;
416*9a747e4fSDavid du Colombier 	if((f->ram->qid.type&QTDIR) == 0)
417*9a747e4fSDavid du Colombier 		return Enotdir;
418*9a747e4fSDavid du Colombier 	/* must be able to write parent */
419*9a747e4fSDavid du Colombier #ifdef CHECKS
420*9a747e4fSDavid du Colombier 	if(!perm(f, f->ram, Pwrite))
421*9a747e4fSDavid du Colombier 		return Eperm;
422*9a747e4fSDavid du Colombier #endif
423*9a747e4fSDavid du Colombier 	prm = thdr.perm;
424*9a747e4fSDavid du Colombier 	name = thdr.name;
425*9a747e4fSDavid du Colombier 	if(strcmp(name, ".")==0 || strcmp(name, "..")==0)
426*9a747e4fSDavid du Colombier 		return Ename;
427*9a747e4fSDavid du Colombier 	for(r=ram; r<&ram[nram]; r++)
428*9a747e4fSDavid du Colombier 		if(r->busy && parent==r->parent)
429*9a747e4fSDavid du Colombier 		if(strcmp((char*)name, r->name)==0)
430*9a747e4fSDavid du Colombier 			return Einuse;
431*9a747e4fSDavid du Colombier 	for(r=ram; r->busy; r++)
432*9a747e4fSDavid du Colombier 		if(r == &ram[Nram-1])
433*9a747e4fSDavid du Colombier 			return "no free ram resources";
434*9a747e4fSDavid du Colombier 	r->busy = 1;
435*9a747e4fSDavid du Colombier 	r->qid.path = ++path;
436*9a747e4fSDavid du Colombier 	r->qid.vers = 0;
437*9a747e4fSDavid du Colombier 	if(prm & DMDIR)
438*9a747e4fSDavid du Colombier 		r->qid.type |= QTDIR;
439*9a747e4fSDavid du Colombier 	r->parent = parent;
440*9a747e4fSDavid du Colombier 	free(r->name);
441*9a747e4fSDavid du Colombier 	r->name = estrdup(name);
442*9a747e4fSDavid du Colombier 	r->user = f->user;
443*9a747e4fSDavid du Colombier 	r->group = f->ram->group;
444*9a747e4fSDavid du Colombier 	r->muid = f->ram->muid;
445*9a747e4fSDavid du Colombier 	if(prm & DMDIR)
446*9a747e4fSDavid du Colombier 		prm = (prm&~0777) | (f->ram->perm&prm&0777);
447*9a747e4fSDavid du Colombier 	else
448*9a747e4fSDavid du Colombier 		prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666);
449*9a747e4fSDavid du Colombier 	r->perm = prm;
450*9a747e4fSDavid du Colombier 	r->ndata = 0;
451*9a747e4fSDavid du Colombier 	if(r-ram >= nram)
452*9a747e4fSDavid du Colombier 		nram = r - ram + 1;
453*9a747e4fSDavid du Colombier 	r->atime = time(0);
454*9a747e4fSDavid du Colombier 	r->mtime = r->atime;
455*9a747e4fSDavid du Colombier 	f->ram->mtime = r->atime;
456*9a747e4fSDavid du Colombier 	f->ram = r;
457*9a747e4fSDavid du Colombier 	rhdr.qid = r->qid;
458*9a747e4fSDavid du Colombier 	rhdr.iounit = messagesize-IOHDRSZ;
459*9a747e4fSDavid du Colombier 	f->open = 1;
460*9a747e4fSDavid du Colombier 	if(thdr.mode & ORCLOSE)
461*9a747e4fSDavid du Colombier 		f->rclose = 1;
462*9a747e4fSDavid du Colombier 	r->open++;
463*9a747e4fSDavid du Colombier 	return 0;
464*9a747e4fSDavid du Colombier }
465*9a747e4fSDavid du Colombier 
466*9a747e4fSDavid du Colombier char*
rread(Fid * f)467*9a747e4fSDavid du Colombier rread(Fid *f)
468*9a747e4fSDavid du Colombier {
469*9a747e4fSDavid du Colombier 	Ram *r;
470*9a747e4fSDavid du Colombier 	uchar *buf;
471*9a747e4fSDavid du Colombier 	long off;
472*9a747e4fSDavid du Colombier 	int n, m, cnt;
473*9a747e4fSDavid du Colombier 
474*9a747e4fSDavid du Colombier 	if(f->ram->busy == 0)
475*9a747e4fSDavid du Colombier 		return Enotexist;
476*9a747e4fSDavid du Colombier 	n = 0;
477*9a747e4fSDavid du Colombier 	rhdr.count = 0;
478*9a747e4fSDavid du Colombier 	off = thdr.offset;
479*9a747e4fSDavid du Colombier 	buf = rdata;
480*9a747e4fSDavid du Colombier 	cnt = thdr.count;
481*9a747e4fSDavid du Colombier 	if(cnt > messagesize)	/* shouldn't happen, anyway */
482*9a747e4fSDavid du Colombier 		cnt = messagesize;
483*9a747e4fSDavid du Colombier 	if(f->ram->qid.type & QTDIR){
484*9a747e4fSDavid du Colombier 		for(r=ram+1; off > 0; r++){
485*9a747e4fSDavid du Colombier 			if(r->busy && r->parent==f->ram-ram)
486*9a747e4fSDavid du Colombier 				off -= ramstat(r, statbuf, sizeof statbuf);
487*9a747e4fSDavid du Colombier 			if(r == &ram[nram-1])
488*9a747e4fSDavid du Colombier 				return 0;
489*9a747e4fSDavid du Colombier 		}
490*9a747e4fSDavid du Colombier 		for(; r<&ram[nram] && n < cnt; r++){
491*9a747e4fSDavid du Colombier 			if(!r->busy || r->parent!=f->ram-ram)
492*9a747e4fSDavid du Colombier 				continue;
493*9a747e4fSDavid du Colombier 			m = ramstat(r, buf+n, cnt-n);
494*9a747e4fSDavid du Colombier 			if(m == 0)
495*9a747e4fSDavid du Colombier 				break;
496*9a747e4fSDavid du Colombier 			n += m;
497*9a747e4fSDavid du Colombier 		}
498*9a747e4fSDavid du Colombier 		rhdr.data = (char*)rdata;
499*9a747e4fSDavid du Colombier 		rhdr.count = n;
500*9a747e4fSDavid du Colombier 		return 0;
501*9a747e4fSDavid du Colombier 	}
502*9a747e4fSDavid du Colombier 	r = f->ram;
503*9a747e4fSDavid du Colombier 	if(off >= r->ndata)
504*9a747e4fSDavid du Colombier 		return 0;
505*9a747e4fSDavid du Colombier 	r->atime = time(0);
506*9a747e4fSDavid du Colombier 	n = cnt;
507*9a747e4fSDavid du Colombier 	if(off+n > r->ndata)
508*9a747e4fSDavid du Colombier 		n = r->ndata - off;
509*9a747e4fSDavid du Colombier 	rhdr.data = r->data+off;
510*9a747e4fSDavid du Colombier 	rhdr.count = n;
511*9a747e4fSDavid du Colombier 	return 0;
512*9a747e4fSDavid du Colombier }
513*9a747e4fSDavid du Colombier 
514*9a747e4fSDavid du Colombier char*
rwrite(Fid * f)515*9a747e4fSDavid du Colombier rwrite(Fid *f)
516*9a747e4fSDavid du Colombier {
517*9a747e4fSDavid du Colombier 	Ram *r;
518*9a747e4fSDavid du Colombier 	ulong off;
519*9a747e4fSDavid du Colombier 	int cnt;
520*9a747e4fSDavid du Colombier 
521*9a747e4fSDavid du Colombier 	r = f->ram;
522*9a747e4fSDavid du Colombier 	if(r->busy == 0)
523*9a747e4fSDavid du Colombier 		return Enotexist;
524*9a747e4fSDavid du Colombier 	off = thdr.offset;
525*9a747e4fSDavid du Colombier 	if(r->perm & DMAPPEND)
526*9a747e4fSDavid du Colombier 		off = r->ndata;
527*9a747e4fSDavid du Colombier 	cnt = thdr.count;
528*9a747e4fSDavid du Colombier 	if(r->qid.type & QTDIR)
529*9a747e4fSDavid du Colombier 		return Eisdir;
530*9a747e4fSDavid du Colombier 	if(off+cnt >= Maxsize)		/* sanity check */
531*9a747e4fSDavid du Colombier 		return "write too big";
532*9a747e4fSDavid du Colombier 	if(off+cnt > r->ndata)
533*9a747e4fSDavid du Colombier 		r->data = erealloc(r->data, off+cnt);
534*9a747e4fSDavid du Colombier 	if(off > r->ndata)
535*9a747e4fSDavid du Colombier 		memset(r->data+r->ndata, 0, off-r->ndata);
536*9a747e4fSDavid du Colombier 	if(off+cnt > r->ndata)
537*9a747e4fSDavid du Colombier 		r->ndata = off+cnt;
538*9a747e4fSDavid du Colombier 	memmove(r->data+off, thdr.data, cnt);
539*9a747e4fSDavid du Colombier 	r->qid.vers++;
540*9a747e4fSDavid du Colombier 	r->mtime = time(0);
541*9a747e4fSDavid du Colombier 	rhdr.count = cnt;
542*9a747e4fSDavid du Colombier 	return 0;
543*9a747e4fSDavid du Colombier }
544*9a747e4fSDavid du Colombier 
545*9a747e4fSDavid du Colombier void
realremove(Ram * r)546*9a747e4fSDavid du Colombier realremove(Ram *r)
547*9a747e4fSDavid du Colombier {
548*9a747e4fSDavid du Colombier 	r->ndata = 0;
549*9a747e4fSDavid du Colombier 	if(r->data)
550*9a747e4fSDavid du Colombier 		free(r->data);
551*9a747e4fSDavid du Colombier 	r->data = 0;
552*9a747e4fSDavid du Colombier 	r->parent = 0;
553*9a747e4fSDavid du Colombier 	memset(&r->qid, 0, sizeof r->qid);
554*9a747e4fSDavid du Colombier 	free(r->name);
555*9a747e4fSDavid du Colombier 	r->name = nil;
556*9a747e4fSDavid du Colombier 	r->busy = 0;
557*9a747e4fSDavid du Colombier }
558*9a747e4fSDavid du Colombier 
559*9a747e4fSDavid du Colombier char *
rclunk(Fid * f)560*9a747e4fSDavid du Colombier rclunk(Fid *f)
561*9a747e4fSDavid du Colombier {
562*9a747e4fSDavid du Colombier 	if(f->open)
563*9a747e4fSDavid du Colombier 		f->ram->open--;
564*9a747e4fSDavid du Colombier 	if(f->rclose)
565*9a747e4fSDavid du Colombier 		realremove(f->ram);
566*9a747e4fSDavid du Colombier 	f->busy = 0;
567*9a747e4fSDavid du Colombier 	f->open = 0;
568*9a747e4fSDavid du Colombier 	f->ram = 0;
569*9a747e4fSDavid du Colombier 	return 0;
570*9a747e4fSDavid du Colombier }
571*9a747e4fSDavid du Colombier 
572*9a747e4fSDavid du Colombier char *
rremove(Fid * f)573*9a747e4fSDavid du Colombier rremove(Fid *f)
574*9a747e4fSDavid du Colombier {
575*9a747e4fSDavid du Colombier 	Ram *r;
576*9a747e4fSDavid du Colombier 
577*9a747e4fSDavid du Colombier 	if(f->open)
578*9a747e4fSDavid du Colombier 		f->ram->open--;
579*9a747e4fSDavid du Colombier 	f->busy = 0;
580*9a747e4fSDavid du Colombier 	f->open = 0;
581*9a747e4fSDavid du Colombier 	r = f->ram;
582*9a747e4fSDavid du Colombier 	f->ram = 0;
583*9a747e4fSDavid du Colombier #ifdef CHECKS
584*9a747e4fSDavid du Colombier 	if(r->qid.path == 0 || !perm(f, &ram[r->parent], Pwrite))
585*9a747e4fSDavid du Colombier 		return Eperm;
586*9a747e4fSDavid du Colombier #endif
587*9a747e4fSDavid du Colombier 	ram[r->parent].mtime = time(0);
588*9a747e4fSDavid du Colombier 	realremove(r);
589*9a747e4fSDavid du Colombier 	return 0;
590*9a747e4fSDavid du Colombier }
591*9a747e4fSDavid du Colombier 
592*9a747e4fSDavid du Colombier char *
rstat(Fid * f)593*9a747e4fSDavid du Colombier rstat(Fid *f)
594*9a747e4fSDavid du Colombier {
595*9a747e4fSDavid du Colombier 	if(f->ram->busy == 0)
596*9a747e4fSDavid du Colombier 		return Enotexist;
597*9a747e4fSDavid du Colombier 	rhdr.nstat = ramstat(f->ram, statbuf, sizeof statbuf);
598*9a747e4fSDavid du Colombier 	rhdr.stat = statbuf;
599*9a747e4fSDavid du Colombier 	return 0;
600*9a747e4fSDavid du Colombier }
601*9a747e4fSDavid du Colombier 
602*9a747e4fSDavid du Colombier char *
rwstat(Fid * f)603*9a747e4fSDavid du Colombier rwstat(Fid *f)
604*9a747e4fSDavid du Colombier {
605*9a747e4fSDavid du Colombier 	Ram *r, *s;
606*9a747e4fSDavid du Colombier 	Dir dir;
607*9a747e4fSDavid du Colombier 
608*9a747e4fSDavid du Colombier 	if(f->ram->busy == 0)
609*9a747e4fSDavid du Colombier 		return Enotexist;
610*9a747e4fSDavid du Colombier 	convM2D(thdr.stat, thdr.nstat, &dir, (char*)statbuf);
611*9a747e4fSDavid du Colombier 	r = f->ram;
612*9a747e4fSDavid du Colombier 
613*9a747e4fSDavid du Colombier 	/*
614*9a747e4fSDavid du Colombier 	 * To change length, must have write permission on file.
615*9a747e4fSDavid du Colombier 	 */
616*9a747e4fSDavid du Colombier #ifdef CHECKS
617*9a747e4fSDavid du Colombier 	if(dir.length!=~0 && dir.length!=r->ndata){
618*9a747e4fSDavid du Colombier 	 	if(!perm(f, r, Pwrite))
619*9a747e4fSDavid du Colombier 			return Eperm;
620*9a747e4fSDavid du Colombier 	}
621*9a747e4fSDavid du Colombier #endif
622*9a747e4fSDavid du Colombier 
623*9a747e4fSDavid du Colombier 	/*
624*9a747e4fSDavid du Colombier 	 * To change name, must have write permission in parent
625*9a747e4fSDavid du Colombier 	 * and name must be unique.
626*9a747e4fSDavid du Colombier 	 */
627*9a747e4fSDavid du Colombier 	if(dir.name[0]!='\0' && strcmp(dir.name, r->name)!=0){
628*9a747e4fSDavid du Colombier #ifdef CHECKS
629*9a747e4fSDavid du Colombier 	 	if(!perm(f, &ram[r->parent], Pwrite))
630*9a747e4fSDavid du Colombier 			return Eperm;
631*9a747e4fSDavid du Colombier #endif
632*9a747e4fSDavid du Colombier 		for(s=ram; s<&ram[nram]; s++)
633*9a747e4fSDavid du Colombier 			if(s->busy && s->parent==r->parent)
634*9a747e4fSDavid du Colombier 			if(strcmp(dir.name, s->name)==0)
635*9a747e4fSDavid du Colombier 				return Eexist;
636*9a747e4fSDavid du Colombier 	}
637*9a747e4fSDavid du Colombier 
638*9a747e4fSDavid du Colombier #ifdef OWNERS
639*9a747e4fSDavid du Colombier 	/*
640*9a747e4fSDavid du Colombier 	 * To change mode, must be owner or group leader.
641*9a747e4fSDavid du Colombier 	 * Because of lack of users file, leader=>group itself.
642*9a747e4fSDavid du Colombier 	 */
643*9a747e4fSDavid du Colombier 	if(dir.mode!=~0 && r->perm!=dir.mode){
644*9a747e4fSDavid du Colombier 		if(strcmp(f->user, r->user) != 0)
645*9a747e4fSDavid du Colombier 		if(strcmp(f->user, r->group) != 0)
646*9a747e4fSDavid du Colombier 			return Enotowner;
647*9a747e4fSDavid du Colombier 	}
648*9a747e4fSDavid du Colombier 
649*9a747e4fSDavid du Colombier 	/*
650*9a747e4fSDavid du Colombier 	 * To change group, must be owner and member of new group,
651*9a747e4fSDavid du Colombier 	 * or leader of current group and leader of new group.
652*9a747e4fSDavid du Colombier 	 * Second case cannot happen, but we check anyway.
653*9a747e4fSDavid du Colombier 	 */
654*9a747e4fSDavid du Colombier 	if(dir.gid[0]!='\0' && strcmp(r->group, dir.gid)!=0){
655*9a747e4fSDavid du Colombier 		if(strcmp(f->user, r->user) == 0)
656*9a747e4fSDavid du Colombier 		if(strcmp(f->user, dir.gid) == 0)
657*9a747e4fSDavid du Colombier 			goto ok;
658*9a747e4fSDavid du Colombier 		if(strcmp(f->user, r->group) == 0)
659*9a747e4fSDavid du Colombier 		if(strcmp(f->user, dir.gid) == 0)
660*9a747e4fSDavid du Colombier 			goto ok;
661*9a747e4fSDavid du Colombier 		return Enotowner;
662*9a747e4fSDavid du Colombier 		ok:;
663*9a747e4fSDavid du Colombier 	}
664*9a747e4fSDavid du Colombier #endif
665*9a747e4fSDavid du Colombier 
666*9a747e4fSDavid du Colombier 	/* all ok; do it */
667*9a747e4fSDavid du Colombier 	if(dir.mode != ~0){
668*9a747e4fSDavid du Colombier 		dir.mode &= ~DMDIR;	/* cannot change dir bit */
669*9a747e4fSDavid du Colombier 		dir.mode |= r->perm&DMDIR;
670*9a747e4fSDavid du Colombier 		r->perm = dir.mode;
671*9a747e4fSDavid du Colombier 	}
672*9a747e4fSDavid du Colombier 	if(dir.name[0] != '\0'){
673*9a747e4fSDavid du Colombier 		free(r->name);
674*9a747e4fSDavid du Colombier 		r->name = estrdup(dir.name);
675*9a747e4fSDavid du Colombier 	}
676*9a747e4fSDavid du Colombier 	if(dir.gid[0] != '\0')
677*9a747e4fSDavid du Colombier 		r->group = atom(dir.gid);
678*9a747e4fSDavid du Colombier 
679*9a747e4fSDavid du Colombier 	if(dir.uid[0] != '\0')
680*9a747e4fSDavid du Colombier 		r->user = atom(dir.uid);
681*9a747e4fSDavid du Colombier 
682*9a747e4fSDavid du Colombier 	if(dir.length!=~0 && dir.length!=r->ndata){
683*9a747e4fSDavid du Colombier 		r->data = erealloc(r->data, dir.length);
684*9a747e4fSDavid du Colombier 		if(r->ndata < dir.length)
685*9a747e4fSDavid du Colombier 			memset(r->data+r->ndata, 0, dir.length-r->ndata);
686*9a747e4fSDavid du Colombier 		r->ndata = dir.length;
687*9a747e4fSDavid du Colombier 	}
688*9a747e4fSDavid du Colombier 
689*9a747e4fSDavid du Colombier 	if(dir.mtime != ~0)
690*9a747e4fSDavid du Colombier 		r->mtime = dir.mtime;
691*9a747e4fSDavid du Colombier 
692*9a747e4fSDavid du Colombier 	ram[r->parent].mtime = time(0);
693*9a747e4fSDavid du Colombier 	return 0;
694*9a747e4fSDavid du Colombier }
695*9a747e4fSDavid du Colombier 
696*9a747e4fSDavid du Colombier uint
ramstat(Ram * r,uchar * buf,uint nbuf)697*9a747e4fSDavid du Colombier ramstat(Ram *r, uchar *buf, uint nbuf)
698*9a747e4fSDavid du Colombier {
699*9a747e4fSDavid du Colombier 	Dir dir;
700*9a747e4fSDavid du Colombier 
701*9a747e4fSDavid du Colombier 	dir.name = r->name;
702*9a747e4fSDavid du Colombier 	dir.qid = r->qid;
703*9a747e4fSDavid du Colombier 	dir.mode = r->perm;
704*9a747e4fSDavid du Colombier 	dir.length = r->ndata;
705*9a747e4fSDavid du Colombier 	dir.uid = r->user;
706*9a747e4fSDavid du Colombier 	dir.gid = r->group;
707*9a747e4fSDavid du Colombier 	dir.muid = r->muid;
708*9a747e4fSDavid du Colombier 	dir.atime = r->atime;
709*9a747e4fSDavid du Colombier 	dir.mtime = r->mtime;
710*9a747e4fSDavid du Colombier 	return convD2M(&dir, buf, nbuf);
711*9a747e4fSDavid du Colombier }
712*9a747e4fSDavid du Colombier 
713*9a747e4fSDavid du Colombier Fid *
newfid(int fid)714*9a747e4fSDavid du Colombier newfid(int fid)
715*9a747e4fSDavid du Colombier {
716*9a747e4fSDavid du Colombier 	Fid *f, *ff;
717*9a747e4fSDavid du Colombier 
718*9a747e4fSDavid du Colombier 	ff = 0;
719*9a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next)
720*9a747e4fSDavid du Colombier 		if(f->fid == fid)
721*9a747e4fSDavid du Colombier 			return f;
722*9a747e4fSDavid du Colombier 		else if(!ff && !f->busy)
723*9a747e4fSDavid du Colombier 			ff = f;
724*9a747e4fSDavid du Colombier 	if(ff){
725*9a747e4fSDavid du Colombier 		ff->fid = fid;
726*9a747e4fSDavid du Colombier 		return ff;
727*9a747e4fSDavid du Colombier 	}
728*9a747e4fSDavid du Colombier 	f = emalloc(sizeof *f);
729*9a747e4fSDavid du Colombier 	f->ram = nil;
730*9a747e4fSDavid du Colombier 	f->fid = fid;
731*9a747e4fSDavid du Colombier 	f->next = fids;
732*9a747e4fSDavid du Colombier 	fids = f;
733*9a747e4fSDavid du Colombier 	return f;
734*9a747e4fSDavid du Colombier }
735*9a747e4fSDavid du Colombier 
736*9a747e4fSDavid du Colombier void
io(void)737*9a747e4fSDavid du Colombier io(void)
738*9a747e4fSDavid du Colombier {
739*9a747e4fSDavid du Colombier 	char *err;
740*9a747e4fSDavid du Colombier 	int n, pid;
741*9a747e4fSDavid du Colombier 
742*9a747e4fSDavid du Colombier 	pid = getpid();
743*9a747e4fSDavid du Colombier 
744*9a747e4fSDavid du Colombier 	for(;;){
745*9a747e4fSDavid du Colombier 		/*
746*9a747e4fSDavid du Colombier 		 * reading from a pipe or a network device
747*9a747e4fSDavid du Colombier 		 * will give an error after a few eof reads.
748*9a747e4fSDavid du Colombier 		 * however, we cannot tell the difference
749*9a747e4fSDavid du Colombier 		 * between a zero-length read and an interrupt
750*9a747e4fSDavid du Colombier 		 * on the processes writing to us,
751*9a747e4fSDavid du Colombier 		 * so we wait for the error.
752*9a747e4fSDavid du Colombier 		 */
753*9a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, messagesize);
754*9a747e4fSDavid du Colombier 		if(n < 0)
755*9a747e4fSDavid du Colombier 			error("mount read: %r");
756*9a747e4fSDavid du Colombier 		if(n == 0)
757*9a747e4fSDavid du Colombier 			continue;
758*9a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &thdr) == 0)
759*9a747e4fSDavid du Colombier 			continue;
760*9a747e4fSDavid du Colombier 
761*9a747e4fSDavid du Colombier 		if(debug)
762*9a747e4fSDavid du Colombier 			fprint(2, "ramfs %d:<-%F\n", pid, &thdr);
763*9a747e4fSDavid du Colombier 
764*9a747e4fSDavid du Colombier 		if(!fcalls[thdr.type])
765*9a747e4fSDavid du Colombier 			err = "bad fcall type";
766*9a747e4fSDavid du Colombier 		else
767*9a747e4fSDavid du Colombier 			err = (*fcalls[thdr.type])(newfid(thdr.fid));
768*9a747e4fSDavid du Colombier 		if(err){
769*9a747e4fSDavid du Colombier 			rhdr.type = Rerror;
770*9a747e4fSDavid du Colombier 			rhdr.ename = err;
771*9a747e4fSDavid du Colombier 		}else{
772*9a747e4fSDavid du Colombier 			rhdr.type = thdr.type + 1;
773*9a747e4fSDavid du Colombier 			rhdr.fid = thdr.fid;
774*9a747e4fSDavid du Colombier 		}
775*9a747e4fSDavid du Colombier 		rhdr.tag = thdr.tag;
776*9a747e4fSDavid du Colombier 		if(debug)
777*9a747e4fSDavid du Colombier 			fprint(2, "ramfs %d:->%F\n", pid, &rhdr);/**/
778*9a747e4fSDavid du Colombier 		n = convS2M(&rhdr, mdata, messagesize);
779*9a747e4fSDavid du Colombier 		if(n == 0)
780*9a747e4fSDavid du Colombier 			error("convS2M error on write");
781*9a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n) != n)
782*9a747e4fSDavid du Colombier 			error("mount write");
783*9a747e4fSDavid du Colombier 	}
784*9a747e4fSDavid du Colombier }
785*9a747e4fSDavid du Colombier 
786*9a747e4fSDavid du Colombier int
perm(Fid * f,Ram * r,int p)787*9a747e4fSDavid du Colombier perm(Fid *f, Ram *r, int p)
788*9a747e4fSDavid du Colombier {
789*9a747e4fSDavid du Colombier 	if((p*Pother) & r->perm)
790*9a747e4fSDavid du Colombier 		return 1;
791*9a747e4fSDavid du Colombier 	if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm))
792*9a747e4fSDavid du Colombier 		return 1;
793*9a747e4fSDavid du Colombier 	if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm))
794*9a747e4fSDavid du Colombier 		return 1;
795*9a747e4fSDavid du Colombier 	return 0;
796*9a747e4fSDavid du Colombier }
797*9a747e4fSDavid du Colombier 
798*9a747e4fSDavid du Colombier void *
emalloc(ulong n)799*9a747e4fSDavid du Colombier emalloc(ulong n)
800*9a747e4fSDavid du Colombier {
801*9a747e4fSDavid du Colombier 	void *p;
802*9a747e4fSDavid du Colombier 
803*9a747e4fSDavid du Colombier 	p = malloc(n);
804*9a747e4fSDavid du Colombier 	if(!p)
805*9a747e4fSDavid du Colombier 		error("out of memory");
806*9a747e4fSDavid du Colombier 	memset(p, 0, n);
807*9a747e4fSDavid du Colombier 	return p;
808*9a747e4fSDavid du Colombier }
809*9a747e4fSDavid du Colombier 
810*9a747e4fSDavid du Colombier void *
erealloc(void * p,ulong n)811*9a747e4fSDavid du Colombier erealloc(void *p, ulong n)
812*9a747e4fSDavid du Colombier {
813*9a747e4fSDavid du Colombier 	p = realloc(p, n);
814*9a747e4fSDavid du Colombier 	if(!p)
815*9a747e4fSDavid du Colombier 		error("out of memory");
816*9a747e4fSDavid du Colombier 	return p;
817*9a747e4fSDavid du Colombier }
818*9a747e4fSDavid du Colombier 
819*9a747e4fSDavid du Colombier char *
estrdup(char * q)820*9a747e4fSDavid du Colombier estrdup(char *q)
821*9a747e4fSDavid du Colombier {
822*9a747e4fSDavid du Colombier 	char *p;
823*9a747e4fSDavid du Colombier 	int n;
824*9a747e4fSDavid du Colombier 
825*9a747e4fSDavid du Colombier 	n = strlen(q)+1;
826*9a747e4fSDavid du Colombier 	p = malloc(n);
827*9a747e4fSDavid du Colombier 	if(!p)
828*9a747e4fSDavid du Colombier 		error("out of memory");
829*9a747e4fSDavid du Colombier 	memmove(p, q, n);
830*9a747e4fSDavid du Colombier 	return p;
831*9a747e4fSDavid du Colombier }
832*9a747e4fSDavid du Colombier 
833*9a747e4fSDavid du Colombier void
ramfsusage(void)834*9a747e4fSDavid du Colombier ramfsusage(void)
835*9a747e4fSDavid du Colombier {
836*9a747e4fSDavid du Colombier 	fprint(2, "usage: %s [-is] [-m mountpoint]\n", argv0);
837*9a747e4fSDavid du Colombier 	exits("usage");
838*9a747e4fSDavid du Colombier }
839*9a747e4fSDavid du Colombier 
840*9a747e4fSDavid du Colombier /*
841*9a747e4fSDavid du Colombier  *	Custom allocators to avoid malloc overheads on small objects.
842*9a747e4fSDavid du Colombier  * 	We never free these.  (See below.)
843*9a747e4fSDavid du Colombier  */
844*9a747e4fSDavid du Colombier typedef struct Stringtab	Stringtab;
845*9a747e4fSDavid du Colombier struct Stringtab {
846*9a747e4fSDavid du Colombier 	Stringtab *link;
847*9a747e4fSDavid du Colombier 	char *str;
848*9a747e4fSDavid du Colombier };
849*9a747e4fSDavid du Colombier static Stringtab*
taballoc(void)850*9a747e4fSDavid du Colombier taballoc(void)
851*9a747e4fSDavid du Colombier {
852*9a747e4fSDavid du Colombier 	static Stringtab *t;
853*9a747e4fSDavid du Colombier 	static uint nt;
854*9a747e4fSDavid du Colombier 
855*9a747e4fSDavid du Colombier 	if(nt == 0){
856*9a747e4fSDavid du Colombier 		t = malloc(64*sizeof(Stringtab));
857*9a747e4fSDavid du Colombier 		if(t == 0)
858*9a747e4fSDavid du Colombier 			sysfatal("out of memory");
859*9a747e4fSDavid du Colombier 		nt = 64;
860*9a747e4fSDavid du Colombier 	}
861*9a747e4fSDavid du Colombier 	nt--;
862*9a747e4fSDavid du Colombier 	return t++;
863*9a747e4fSDavid du Colombier }
864*9a747e4fSDavid du Colombier 
865*9a747e4fSDavid du Colombier static char*
xstrdup(char * s)866*9a747e4fSDavid du Colombier xstrdup(char *s)
867*9a747e4fSDavid du Colombier {
868*9a747e4fSDavid du Colombier 	char *r;
869*9a747e4fSDavid du Colombier 	int len;
870*9a747e4fSDavid du Colombier 	static char *t;
871*9a747e4fSDavid du Colombier 	static int nt;
872*9a747e4fSDavid du Colombier 
873*9a747e4fSDavid du Colombier 	len = strlen(s)+1;
874*9a747e4fSDavid du Colombier 	if(len >= 8192)
875*9a747e4fSDavid du Colombier 		sysfatal("strdup big string");
876*9a747e4fSDavid du Colombier 
877*9a747e4fSDavid du Colombier 	if(nt < len){
878*9a747e4fSDavid du Colombier 		t = malloc(8192);
879*9a747e4fSDavid du Colombier 		if(t == 0)
880*9a747e4fSDavid du Colombier 			sysfatal("out of memory");
881*9a747e4fSDavid du Colombier 		nt = 8192;
882*9a747e4fSDavid du Colombier 	}
883*9a747e4fSDavid du Colombier 	r = t;
884*9a747e4fSDavid du Colombier 	t += len;
885*9a747e4fSDavid du Colombier 	nt -= len;
886*9a747e4fSDavid du Colombier 	strcpy(r, s);
887*9a747e4fSDavid du Colombier 	return r;
888*9a747e4fSDavid du Colombier }
889*9a747e4fSDavid du Colombier 
890*9a747e4fSDavid du Colombier /*
891*9a747e4fSDavid du Colombier  *	Return a uniquely allocated copy of a string.
892*9a747e4fSDavid du Colombier  *	Don't free these -- they stay in the table for the
893*9a747e4fSDavid du Colombier  *	next caller who wants that particular string.
894*9a747e4fSDavid du Colombier  *	String comparison can be done with pointer comparison
895*9a747e4fSDavid du Colombier  *	if you know both strings are atoms.
896*9a747e4fSDavid du Colombier  */
897*9a747e4fSDavid du Colombier static Stringtab *stab[1024];
898*9a747e4fSDavid du Colombier 
899*9a747e4fSDavid du Colombier static uint
hash(char * s)900*9a747e4fSDavid du Colombier hash(char *s)
901*9a747e4fSDavid du Colombier {
902*9a747e4fSDavid du Colombier 	uint h;
903*9a747e4fSDavid du Colombier 	uchar *p;
904*9a747e4fSDavid du Colombier 
905*9a747e4fSDavid du Colombier 	h = 0;
906*9a747e4fSDavid du Colombier 	for(p=(uchar*)s; *p; p++)
907*9a747e4fSDavid du Colombier 		h = h*37 + *p;
908*9a747e4fSDavid du Colombier 	return h;
909*9a747e4fSDavid du Colombier }
910*9a747e4fSDavid du Colombier 
911*9a747e4fSDavid du Colombier char*
atom(char * str)912*9a747e4fSDavid du Colombier atom(char *str)
913*9a747e4fSDavid du Colombier {
914*9a747e4fSDavid du Colombier 	uint h;
915*9a747e4fSDavid du Colombier 	Stringtab *tab;
916*9a747e4fSDavid du Colombier 
917*9a747e4fSDavid du Colombier 	h = hash(str) % nelem(stab);
918*9a747e4fSDavid du Colombier 	for(tab=stab[h]; tab; tab=tab->link)
919*9a747e4fSDavid du Colombier 		if(strcmp(str, tab->str) == 0)
920*9a747e4fSDavid du Colombier 			return tab->str;
921*9a747e4fSDavid du Colombier 
922*9a747e4fSDavid du Colombier 	tab = taballoc();
923*9a747e4fSDavid du Colombier 	tab->str = xstrdup(str);
924*9a747e4fSDavid du Colombier 	tab->link = stab[h];
925*9a747e4fSDavid du Colombier 	stab[h] = tab;
926*9a747e4fSDavid du Colombier 	return tab->str;
927*9a747e4fSDavid du Colombier }
928