xref: /plan9/sys/src/cmd/disk/kfs/9p1.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include	"all.h"
2*9a747e4fSDavid du Colombier #include	"9p1.h"
3*9a747e4fSDavid du Colombier 
4*9a747e4fSDavid du Colombier /*
5*9a747e4fSDavid du Colombier  * buggery to give false qid for
6*9a747e4fSDavid du Colombier  * the top 2 levels of the dump fs
7*9a747e4fSDavid du Colombier  */
8*9a747e4fSDavid du Colombier void
9*9a747e4fSDavid du Colombier mkqid(Qid* qid, Dentry *d, int buggery)
10*9a747e4fSDavid du Colombier {
11*9a747e4fSDavid du Colombier 	int c;
12*9a747e4fSDavid du Colombier 
13*9a747e4fSDavid du Colombier 	if(buggery && d->qid.path == QPROOT && (d->qid.path & QPDIR)){
14*9a747e4fSDavid du Colombier 		c = d->name[0];
15*9a747e4fSDavid du Colombier 		if(c >= '0' && c <= '9'){
16*9a747e4fSDavid du Colombier 			qid->path = 3;
17*9a747e4fSDavid du Colombier 			qid->vers = d->qid.version;
18*9a747e4fSDavid du Colombier 			qid->type = QTDIR;
19*9a747e4fSDavid du Colombier 
20*9a747e4fSDavid du Colombier 			c = (c-'0')*10 + (d->name[1]-'0');
21*9a747e4fSDavid du Colombier 			if(c >= 1 && c <= 12)
22*9a747e4fSDavid du Colombier 				qid->path = 4;
23*9a747e4fSDavid du Colombier 			return;
24*9a747e4fSDavid du Colombier 		}
25*9a747e4fSDavid du Colombier 	}
26*9a747e4fSDavid du Colombier 
27*9a747e4fSDavid du Colombier 	mkqid9p2(qid, &d->qid, d->mode);
28*9a747e4fSDavid du Colombier }
29*9a747e4fSDavid du Colombier 
30*9a747e4fSDavid du Colombier int
31*9a747e4fSDavid du Colombier mkqidcmp(Qid* qid, Dentry *d)
32*9a747e4fSDavid du Colombier {
33*9a747e4fSDavid du Colombier 	Qid tmp;
34*9a747e4fSDavid du Colombier 
35*9a747e4fSDavid du Colombier 	mkqid(&tmp, d, 1);
36*9a747e4fSDavid du Colombier 	if(qid->path==tmp.path && (qid->type&QTDIR)==(tmp.type&QTDIR))
37*9a747e4fSDavid du Colombier 		return 0;
38*9a747e4fSDavid du Colombier 	return Eqid;
39*9a747e4fSDavid du Colombier }
40*9a747e4fSDavid du Colombier 
41*9a747e4fSDavid du Colombier void
42*9a747e4fSDavid du Colombier f_nop(Chan *cp, Oldfcall *in, Oldfcall *ou)
43*9a747e4fSDavid du Colombier {
44*9a747e4fSDavid du Colombier 
45*9a747e4fSDavid du Colombier 	USED(in);
46*9a747e4fSDavid du Colombier 	USED(ou);
47*9a747e4fSDavid du Colombier 	if(CHAT(cp))
48*9a747e4fSDavid du Colombier 		print("c_nop %d\n", cp->chan);
49*9a747e4fSDavid du Colombier }
50*9a747e4fSDavid du Colombier 
51*9a747e4fSDavid du Colombier void
52*9a747e4fSDavid du Colombier f_flush(Chan *cp, Oldfcall *in, Oldfcall *ou)
53*9a747e4fSDavid du Colombier {
54*9a747e4fSDavid du Colombier 
55*9a747e4fSDavid du Colombier 	USED(in);
56*9a747e4fSDavid du Colombier 	USED(ou);
57*9a747e4fSDavid du Colombier 	if(CHAT(cp))
58*9a747e4fSDavid du Colombier 		print("c_flush %d\n", cp->chan);
59*9a747e4fSDavid du Colombier 	runlock(&cp->reflock);
60*9a747e4fSDavid du Colombier 	wlock(&cp->reflock);
61*9a747e4fSDavid du Colombier 	wunlock(&cp->reflock);
62*9a747e4fSDavid du Colombier 	rlock(&cp->reflock);
63*9a747e4fSDavid du Colombier }
64*9a747e4fSDavid du Colombier 
65*9a747e4fSDavid du Colombier void
66*9a747e4fSDavid du Colombier f_session(Chan *cp, Oldfcall *in, Oldfcall *ou)
67*9a747e4fSDavid du Colombier {
68*9a747e4fSDavid du Colombier 	if(CHAT(cp))
69*9a747e4fSDavid du Colombier 		print("c_session %d\n", cp->chan);
70*9a747e4fSDavid du Colombier 
71*9a747e4fSDavid du Colombier 	memmove(cp->rchal, in->chal, sizeof(cp->rchal));
72*9a747e4fSDavid du Colombier 	mkchallenge(cp);
73*9a747e4fSDavid du Colombier 	memmove(ou->chal, cp->chal, sizeof(ou->chal));
74*9a747e4fSDavid du Colombier 	if(wstatallow || cp == cons.srvchan)
75*9a747e4fSDavid du Colombier 		memset(ou->authid, 0, sizeof(ou->authid));
76*9a747e4fSDavid du Colombier 	else
77*9a747e4fSDavid du Colombier 		memmove(ou->authid, nvr.authid, sizeof(ou->authid));
78*9a747e4fSDavid du Colombier 	sprint(ou->authdom, "%s.%s", service, nvr.authdom);
79*9a747e4fSDavid du Colombier 	fileinit(cp);
80*9a747e4fSDavid du Colombier }
81*9a747e4fSDavid du Colombier 
82*9a747e4fSDavid du Colombier void
83*9a747e4fSDavid du Colombier f_attach(Chan *cp, Oldfcall *in, Oldfcall *ou)
84*9a747e4fSDavid du Colombier {
85*9a747e4fSDavid du Colombier 	Iobuf *p;
86*9a747e4fSDavid du Colombier 	Dentry *d;
87*9a747e4fSDavid du Colombier 	File *f;
88*9a747e4fSDavid du Colombier 	int u;
89*9a747e4fSDavid du Colombier 	Filsys *fs;
90*9a747e4fSDavid du Colombier 	long raddr;
91*9a747e4fSDavid du Colombier 
92*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
93*9a747e4fSDavid du Colombier 		print("c_attach %d\n", cp->chan);
94*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
95*9a747e4fSDavid du Colombier 		print("	uid = %s\n", in->uname);
96*9a747e4fSDavid du Colombier 		print("	arg = %s\n", in->aname);
97*9a747e4fSDavid du Colombier 	}
98*9a747e4fSDavid du Colombier 
99*9a747e4fSDavid du Colombier 	ou->qid = QID9P1(0,0);
100*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
101*9a747e4fSDavid du Colombier 	if(!in->aname[0])	/* default */
102*9a747e4fSDavid du Colombier 		strncpy(in->aname, filesys[0].name, sizeof(in->aname));
103*9a747e4fSDavid du Colombier 	p = 0;
104*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 1);
105*9a747e4fSDavid du Colombier 	if(!f) {
106*9a747e4fSDavid du Colombier 		ou->err = Efid;
107*9a747e4fSDavid du Colombier 		goto out;
108*9a747e4fSDavid du Colombier 	}
109*9a747e4fSDavid du Colombier 	u = -1;
110*9a747e4fSDavid du Colombier 	if(cp != cons.chan){
111*9a747e4fSDavid du Colombier 		if(/*authorize(cp, in, ou) == 0 || */strcmp(in->uname, "adm") == 0){
112*9a747e4fSDavid du Colombier 			ou->err = Eauth;
113*9a747e4fSDavid du Colombier 			goto out;
114*9a747e4fSDavid du Colombier 		}
115*9a747e4fSDavid du Colombier 		u = strtouid(in->uname);
116*9a747e4fSDavid du Colombier 		if(u < 0){
117*9a747e4fSDavid du Colombier 			ou->err = Ebadu;
118*9a747e4fSDavid du Colombier 			goto out;
119*9a747e4fSDavid du Colombier 		}
120*9a747e4fSDavid du Colombier 	}
121*9a747e4fSDavid du Colombier 
122*9a747e4fSDavid du Colombier 	fs = fsstr(in->aname);
123*9a747e4fSDavid du Colombier 	if(fs == 0) {
124*9a747e4fSDavid du Colombier 		ou->err = Ebadspc;
125*9a747e4fSDavid du Colombier 		goto out;
126*9a747e4fSDavid du Colombier 	}
127*9a747e4fSDavid du Colombier 	raddr = getraddr(fs->dev);
128*9a747e4fSDavid du Colombier 	p = getbuf(fs->dev, raddr, Bread);
129*9a747e4fSDavid du Colombier 	d = getdir(p, 0);
130*9a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) {
131*9a747e4fSDavid du Colombier 		ou->err = Ealloc;
132*9a747e4fSDavid du Colombier 		goto out;
133*9a747e4fSDavid du Colombier 	}
134*9a747e4fSDavid du Colombier 	f->uid = u;
135*9a747e4fSDavid du Colombier 	if(iaccess(f, d, DREAD)) {
136*9a747e4fSDavid du Colombier 		ou->err = Eaccess;
137*9a747e4fSDavid du Colombier 		goto out;
138*9a747e4fSDavid du Colombier 	}
139*9a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
140*9a747e4fSDavid du Colombier 	mkqid(&f->qid, d, 1);
141*9a747e4fSDavid du Colombier 	f->fs = fs;
142*9a747e4fSDavid du Colombier 	f->addr = raddr;
143*9a747e4fSDavid du Colombier 	f->slot = 0;
144*9a747e4fSDavid du Colombier 	f->open = 0;
145*9a747e4fSDavid du Colombier 	freewp(f->wpath);
146*9a747e4fSDavid du Colombier 	f->wpath = 0;
147*9a747e4fSDavid du Colombier 
148*9a747e4fSDavid du Colombier 	mkqid9p1(&ou->qid, &f->qid);
149*9a747e4fSDavid du Colombier 
150*9a747e4fSDavid du Colombier out:
151*9a747e4fSDavid du Colombier 	if(p)
152*9a747e4fSDavid du Colombier 		putbuf(p);
153*9a747e4fSDavid du Colombier 	if(f) {
154*9a747e4fSDavid du Colombier 		qunlock(f);
155*9a747e4fSDavid du Colombier 		if(ou->err)
156*9a747e4fSDavid du Colombier 			freefp(f);
157*9a747e4fSDavid du Colombier 	}
158*9a747e4fSDavid du Colombier }
159*9a747e4fSDavid du Colombier 
160*9a747e4fSDavid du Colombier void
161*9a747e4fSDavid du Colombier f_clone(Chan *cp, Oldfcall *in, Oldfcall *ou)
162*9a747e4fSDavid du Colombier {
163*9a747e4fSDavid du Colombier 	File *f1, *f2;
164*9a747e4fSDavid du Colombier 	int fid, fid1;
165*9a747e4fSDavid du Colombier 
166*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
167*9a747e4fSDavid du Colombier 		print("c_clone %d\n", cp->chan);
168*9a747e4fSDavid du Colombier 		print("	old fid = %d\n", in->fid);
169*9a747e4fSDavid du Colombier 		print("	new fid = %d\n", in->newfid);
170*9a747e4fSDavid du Colombier 	}
171*9a747e4fSDavid du Colombier 
172*9a747e4fSDavid du Colombier 	fid = in->fid;
173*9a747e4fSDavid du Colombier 	fid1 = in->newfid;
174*9a747e4fSDavid du Colombier 
175*9a747e4fSDavid du Colombier 	f1 = 0;
176*9a747e4fSDavid du Colombier 	f2 = 0;
177*9a747e4fSDavid du Colombier 	if(fid < fid1) {
178*9a747e4fSDavid du Colombier 		f1 = filep(cp, fid, 0);
179*9a747e4fSDavid du Colombier 		f2 = filep(cp, fid1, 1);
180*9a747e4fSDavid du Colombier 	} else
181*9a747e4fSDavid du Colombier 	if(fid1 < fid) {
182*9a747e4fSDavid du Colombier 		f2 = filep(cp, fid1, 1);
183*9a747e4fSDavid du Colombier 		f1 = filep(cp, fid, 0);
184*9a747e4fSDavid du Colombier 	}
185*9a747e4fSDavid du Colombier 	if(!f1 || !f2) {
186*9a747e4fSDavid du Colombier 		ou->err = Efid;
187*9a747e4fSDavid du Colombier 		goto out;
188*9a747e4fSDavid du Colombier 	}
189*9a747e4fSDavid du Colombier 
190*9a747e4fSDavid du Colombier 
191*9a747e4fSDavid du Colombier 	f2->fs = f1->fs;
192*9a747e4fSDavid du Colombier 	f2->addr = f1->addr;
193*9a747e4fSDavid du Colombier 	f2->open = f1->open & ~FREMOV;
194*9a747e4fSDavid du Colombier 	f2->uid = f1->uid;
195*9a747e4fSDavid du Colombier 	f2->slot = f1->slot;
196*9a747e4fSDavid du Colombier 	f2->qid = f1->qid;
197*9a747e4fSDavid du Colombier 
198*9a747e4fSDavid du Colombier 	freewp(f2->wpath);
199*9a747e4fSDavid du Colombier 	f2->wpath = getwp(f1->wpath);
200*9a747e4fSDavid du Colombier 
201*9a747e4fSDavid du Colombier out:
202*9a747e4fSDavid du Colombier 	ou->fid = fid;
203*9a747e4fSDavid du Colombier 	if(f1)
204*9a747e4fSDavid du Colombier 		qunlock(f1);
205*9a747e4fSDavid du Colombier 	if(f2)
206*9a747e4fSDavid du Colombier 		qunlock(f2);
207*9a747e4fSDavid du Colombier }
208*9a747e4fSDavid du Colombier 
209*9a747e4fSDavid du Colombier void
210*9a747e4fSDavid du Colombier f_walk(Chan *cp, Oldfcall *in, Oldfcall *ou)
211*9a747e4fSDavid du Colombier {
212*9a747e4fSDavid du Colombier 	Iobuf *p, *p1;
213*9a747e4fSDavid du Colombier 	Dentry *d, *d1;
214*9a747e4fSDavid du Colombier 	File *f;
215*9a747e4fSDavid du Colombier 	Wpath *w, *ow;
216*9a747e4fSDavid du Colombier 	int slot;
217*9a747e4fSDavid du Colombier 	long addr;
218*9a747e4fSDavid du Colombier 
219*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
220*9a747e4fSDavid du Colombier 		print("c_walk %d\n", cp->chan);
221*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
222*9a747e4fSDavid du Colombier 		print("	name = %s\n", in->name);
223*9a747e4fSDavid du Colombier 	}
224*9a747e4fSDavid du Colombier 
225*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
226*9a747e4fSDavid du Colombier 	ou->qid = QID9P1(0,0);
227*9a747e4fSDavid du Colombier 	p = 0;
228*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
229*9a747e4fSDavid du Colombier 	if(!f) {
230*9a747e4fSDavid du Colombier 		ou->err = Efid;
231*9a747e4fSDavid du Colombier 		goto out;
232*9a747e4fSDavid du Colombier 	}
233*9a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
234*9a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
235*9a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
236*9a747e4fSDavid du Colombier 		ou->err = Ealloc;
237*9a747e4fSDavid du Colombier 		goto out;
238*9a747e4fSDavid du Colombier 	}
239*9a747e4fSDavid du Colombier 	if(!(d->mode & DDIR)) {
240*9a747e4fSDavid du Colombier 		ou->err = Edir1;
241*9a747e4fSDavid du Colombier 		goto out;
242*9a747e4fSDavid du Colombier 	}
243*9a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
244*9a747e4fSDavid du Colombier 		goto out;
245*9a747e4fSDavid du Colombier 	if(cp != cons.chan && iaccess(f, d, DEXEC)) {
246*9a747e4fSDavid du Colombier 		ou->err = Eaccess;
247*9a747e4fSDavid du Colombier 		goto out;
248*9a747e4fSDavid du Colombier 	}
249*9a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
250*9a747e4fSDavid du Colombier 	if(strcmp(in->name, ".") == 0)
251*9a747e4fSDavid du Colombier 		goto setdot;
252*9a747e4fSDavid du Colombier 	if(strcmp(in->name, "..") == 0) {
253*9a747e4fSDavid du Colombier 		if(f->wpath == 0)
254*9a747e4fSDavid du Colombier 			goto setdot;
255*9a747e4fSDavid du Colombier 		putbuf(p);
256*9a747e4fSDavid du Colombier 		p = 0;
257*9a747e4fSDavid du Colombier 		addr = f->wpath->addr;
258*9a747e4fSDavid du Colombier 		slot = f->wpath->slot;
259*9a747e4fSDavid du Colombier 		p1 = getbuf(f->fs->dev, addr, Bread);
260*9a747e4fSDavid du Colombier 		d1 = getdir(p1, slot);
261*9a747e4fSDavid du Colombier 		if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
262*9a747e4fSDavid du Colombier 			if(p1)
263*9a747e4fSDavid du Colombier 				putbuf(p1);
264*9a747e4fSDavid du Colombier 			ou->err = Ephase;
265*9a747e4fSDavid du Colombier 			goto out;
266*9a747e4fSDavid du Colombier 		}
267*9a747e4fSDavid du Colombier 		ow = f->wpath;
268*9a747e4fSDavid du Colombier 		f->wpath = ow->up;
269*9a747e4fSDavid du Colombier 		putwp(ow);
270*9a747e4fSDavid du Colombier 		goto found;
271*9a747e4fSDavid du Colombier 	}
272*9a747e4fSDavid du Colombier 	for(addr=0;; addr++) {
273*9a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0);
274*9a747e4fSDavid du Colombier 		if(!p1 || checktag(p1, Tdir, d->qid.path) ) {
275*9a747e4fSDavid du Colombier 			if(p1)
276*9a747e4fSDavid du Colombier 				putbuf(p1);
277*9a747e4fSDavid du Colombier 			ou->err = Eentry;
278*9a747e4fSDavid du Colombier 			goto out;
279*9a747e4fSDavid du Colombier 		}
280*9a747e4fSDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
281*9a747e4fSDavid du Colombier 			d1 = getdir(p1, slot);
282*9a747e4fSDavid du Colombier 			if(!(d1->mode & DALLOC))
283*9a747e4fSDavid du Colombier 				continue;
284*9a747e4fSDavid du Colombier 			if(strncmp(in->name, d1->name, sizeof(in->name)))
285*9a747e4fSDavid du Colombier 				continue;
286*9a747e4fSDavid du Colombier 			/*
287*9a747e4fSDavid du Colombier 			 * update walk path
288*9a747e4fSDavid du Colombier 			 */
289*9a747e4fSDavid du Colombier 			w = newwp();
290*9a747e4fSDavid du Colombier 			if(!w) {
291*9a747e4fSDavid du Colombier 				ou->err = Ewalk;
292*9a747e4fSDavid du Colombier 				putbuf(p1);
293*9a747e4fSDavid du Colombier 				goto out;
294*9a747e4fSDavid du Colombier 			}
295*9a747e4fSDavid du Colombier 			w->addr = f->addr;
296*9a747e4fSDavid du Colombier 			w->slot = f->slot;
297*9a747e4fSDavid du Colombier 			w->up = f->wpath;
298*9a747e4fSDavid du Colombier 			f->wpath = w;
299*9a747e4fSDavid du Colombier 			slot += DIRPERBUF*addr;
300*9a747e4fSDavid du Colombier 			goto found;
301*9a747e4fSDavid du Colombier 		}
302*9a747e4fSDavid du Colombier 		putbuf(p1);
303*9a747e4fSDavid du Colombier 	}
304*9a747e4fSDavid du Colombier 
305*9a747e4fSDavid du Colombier found:
306*9a747e4fSDavid du Colombier 	f->addr = p1->addr;
307*9a747e4fSDavid du Colombier 	mkqid(&f->qid, d1, 1);
308*9a747e4fSDavid du Colombier 	putbuf(p1);
309*9a747e4fSDavid du Colombier 	f->slot = slot;
310*9a747e4fSDavid du Colombier 
311*9a747e4fSDavid du Colombier setdot:
312*9a747e4fSDavid du Colombier 	mkqid9p1(&ou->qid, &f->qid);
313*9a747e4fSDavid du Colombier 	f->open = 0;
314*9a747e4fSDavid du Colombier 
315*9a747e4fSDavid du Colombier out:
316*9a747e4fSDavid du Colombier 	if(p)
317*9a747e4fSDavid du Colombier 		putbuf(p);
318*9a747e4fSDavid du Colombier 	if(f)
319*9a747e4fSDavid du Colombier 		qunlock(f);
320*9a747e4fSDavid du Colombier }
321*9a747e4fSDavid du Colombier 
322*9a747e4fSDavid du Colombier void
323*9a747e4fSDavid du Colombier f_clunk(Chan *cp, Oldfcall *in, Oldfcall *ou)
324*9a747e4fSDavid du Colombier {
325*9a747e4fSDavid du Colombier 	File *f;
326*9a747e4fSDavid du Colombier 	Tlock *t;
327*9a747e4fSDavid du Colombier 	long tim;
328*9a747e4fSDavid du Colombier 
329*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
330*9a747e4fSDavid du Colombier 		print("c_clunk %d\n", cp->chan);
331*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
332*9a747e4fSDavid du Colombier 	}
333*9a747e4fSDavid du Colombier 
334*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
335*9a747e4fSDavid du Colombier 	if(!f) {
336*9a747e4fSDavid du Colombier 		print("%p\n", f);
337*9a747e4fSDavid du Colombier 		ou->err = Efid;
338*9a747e4fSDavid du Colombier 		goto out;
339*9a747e4fSDavid du Colombier 	}
340*9a747e4fSDavid du Colombier 	if(t = f->tlock) {
341*9a747e4fSDavid du Colombier 		tim = time(0);
342*9a747e4fSDavid du Colombier 		if(t->time < tim || t->file != f)
343*9a747e4fSDavid du Colombier 			ou->err = Ebroken;
344*9a747e4fSDavid du Colombier 		t->time = 0;	/* free the lock */
345*9a747e4fSDavid du Colombier 		f->tlock = 0;
346*9a747e4fSDavid du Colombier 	}
347*9a747e4fSDavid du Colombier 	if(f->open & FREMOV)
348*9a747e4fSDavid du Colombier 		ou->err = doremove(f, 0);
349*9a747e4fSDavid du Colombier 	f->open = 0;
350*9a747e4fSDavid du Colombier 	freewp(f->wpath);
351*9a747e4fSDavid du Colombier 	freefp(f);
352*9a747e4fSDavid du Colombier 
353*9a747e4fSDavid du Colombier out:
354*9a747e4fSDavid du Colombier 	if(f)
355*9a747e4fSDavid du Colombier 		qunlock(f);
356*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
357*9a747e4fSDavid du Colombier }
358*9a747e4fSDavid du Colombier 
359*9a747e4fSDavid du Colombier void
360*9a747e4fSDavid du Colombier f_clwalk(Chan *cp, Oldfcall *in, Oldfcall *ou)
361*9a747e4fSDavid du Colombier {
362*9a747e4fSDavid du Colombier 	int er, fid;
363*9a747e4fSDavid du Colombier 
364*9a747e4fSDavid du Colombier 	if(CHAT(cp))
365*9a747e4fSDavid du Colombier 		print("c_clwalk macro\n");
366*9a747e4fSDavid du Colombier 
367*9a747e4fSDavid du Colombier 	f_clone(cp, in, ou);		/* sets tag, fid */
368*9a747e4fSDavid du Colombier 	if(ou->err)
369*9a747e4fSDavid du Colombier 		return;
370*9a747e4fSDavid du Colombier 	fid = in->fid;
371*9a747e4fSDavid du Colombier 	in->fid = in->newfid;
372*9a747e4fSDavid du Colombier 	f_walk(cp, in, ou);		/* sets tag, fid, qid */
373*9a747e4fSDavid du Colombier 	er = ou->err;
374*9a747e4fSDavid du Colombier 	if(er == Eentry) {
375*9a747e4fSDavid du Colombier 		/*
376*9a747e4fSDavid du Colombier 		 * if error is "no entry"
377*9a747e4fSDavid du Colombier 		 * return non error and fid
378*9a747e4fSDavid du Colombier 		 */
379*9a747e4fSDavid du Colombier 		ou->err = 0;
380*9a747e4fSDavid du Colombier 		f_clunk(cp, in, ou);	/* sets tag, fid */
381*9a747e4fSDavid du Colombier 		ou->err = 0;
382*9a747e4fSDavid du Colombier 		ou->fid = fid;
383*9a747e4fSDavid du Colombier 		if(CHAT(cp))
384*9a747e4fSDavid du Colombier 			print("	error: %s\n", errstring[er]);
385*9a747e4fSDavid du Colombier 		return;
386*9a747e4fSDavid du Colombier 	}
387*9a747e4fSDavid du Colombier 	if(er) {
388*9a747e4fSDavid du Colombier 		/*
389*9a747e4fSDavid du Colombier 		 * if any other error
390*9a747e4fSDavid du Colombier 		 * return an error
391*9a747e4fSDavid du Colombier 		 */
392*9a747e4fSDavid du Colombier 		ou->err = 0;
393*9a747e4fSDavid du Colombier 		f_clunk(cp, in, ou);	/* sets tag, fid */
394*9a747e4fSDavid du Colombier 		ou->err = er;
395*9a747e4fSDavid du Colombier 		return;
396*9a747e4fSDavid du Colombier 	}
397*9a747e4fSDavid du Colombier 	/*
398*9a747e4fSDavid du Colombier 	 * non error
399*9a747e4fSDavid du Colombier 	 * return newfid
400*9a747e4fSDavid du Colombier 	 */
401*9a747e4fSDavid du Colombier }
402*9a747e4fSDavid du Colombier 
403*9a747e4fSDavid du Colombier void
404*9a747e4fSDavid du Colombier f_open(Chan *cp, Oldfcall *in, Oldfcall *ou)
405*9a747e4fSDavid du Colombier {
406*9a747e4fSDavid du Colombier 	Iobuf *p;
407*9a747e4fSDavid du Colombier 	Dentry *d;
408*9a747e4fSDavid du Colombier 	File *f;
409*9a747e4fSDavid du Colombier 	Tlock *t;
410*9a747e4fSDavid du Colombier 	Qid qid;
411*9a747e4fSDavid du Colombier 	int ro, fmod;
412*9a747e4fSDavid du Colombier 
413*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
414*9a747e4fSDavid du Colombier 		print("c_open %d\n", cp->chan);
415*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
416*9a747e4fSDavid du Colombier 		print("	mode = %o\n", in->mode);
417*9a747e4fSDavid du Colombier 	}
418*9a747e4fSDavid du Colombier 
419*9a747e4fSDavid du Colombier 	p = 0;
420*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
421*9a747e4fSDavid du Colombier 	if(!f) {
422*9a747e4fSDavid du Colombier 		ou->err = Efid;
423*9a747e4fSDavid du Colombier 		goto out;
424*9a747e4fSDavid du Colombier 	}
425*9a747e4fSDavid du Colombier 
426*9a747e4fSDavid du Colombier 	/*
427*9a747e4fSDavid du Colombier 	 * if remove on close, check access here
428*9a747e4fSDavid du Colombier 	 */
429*9a747e4fSDavid du Colombier 	ro = isro(f->fs->dev);
430*9a747e4fSDavid du Colombier 	if(in->mode & MRCLOSE) {
431*9a747e4fSDavid du Colombier 		if(ro) {
432*9a747e4fSDavid du Colombier 			ou->err = Eronly;
433*9a747e4fSDavid du Colombier 			goto out;
434*9a747e4fSDavid du Colombier 		}
435*9a747e4fSDavid du Colombier 		/*
436*9a747e4fSDavid du Colombier 		 * check on parent directory of file to be deleted
437*9a747e4fSDavid du Colombier 		 */
438*9a747e4fSDavid du Colombier 		if(f->wpath == 0 || f->wpath->addr == f->addr) {
439*9a747e4fSDavid du Colombier 			ou->err = Ephase;
440*9a747e4fSDavid du Colombier 			goto out;
441*9a747e4fSDavid du Colombier 		}
442*9a747e4fSDavid du Colombier 		p = getbuf(f->fs->dev, f->wpath->addr, Bread);
443*9a747e4fSDavid du Colombier 		d = getdir(p, f->wpath->slot);
444*9a747e4fSDavid du Colombier 		if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
445*9a747e4fSDavid du Colombier 			ou->err = Ephase;
446*9a747e4fSDavid du Colombier 			goto out;
447*9a747e4fSDavid du Colombier 		}
448*9a747e4fSDavid du Colombier 		if(iaccess(f, d, DWRITE)) {
449*9a747e4fSDavid du Colombier 			ou->err = Eaccess;
450*9a747e4fSDavid du Colombier 			goto out;
451*9a747e4fSDavid du Colombier 		}
452*9a747e4fSDavid du Colombier 		putbuf(p);
453*9a747e4fSDavid du Colombier 	}
454*9a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
455*9a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
456*9a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
457*9a747e4fSDavid du Colombier 		ou->err = Ealloc;
458*9a747e4fSDavid du Colombier 		goto out;
459*9a747e4fSDavid du Colombier 	}
460*9a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
461*9a747e4fSDavid du Colombier 		goto out;
462*9a747e4fSDavid du Colombier 	mkqid(&qid, d, 1);
463*9a747e4fSDavid du Colombier 	switch(in->mode & 7) {
464*9a747e4fSDavid du Colombier 
465*9a747e4fSDavid du Colombier 	case MREAD:
466*9a747e4fSDavid du Colombier 		if(iaccess(f, d, DREAD) && !writeallow)
467*9a747e4fSDavid du Colombier 			goto badaccess;
468*9a747e4fSDavid du Colombier 		fmod = FREAD;
469*9a747e4fSDavid du Colombier 		break;
470*9a747e4fSDavid du Colombier 
471*9a747e4fSDavid du Colombier 	case MWRITE:
472*9a747e4fSDavid du Colombier 		if((d->mode & DDIR) ||
473*9a747e4fSDavid du Colombier 		   (iaccess(f, d, DWRITE) && !writeallow))
474*9a747e4fSDavid du Colombier 			goto badaccess;
475*9a747e4fSDavid du Colombier 		if(ro) {
476*9a747e4fSDavid du Colombier 			ou->err = Eronly;
477*9a747e4fSDavid du Colombier 			goto out;
478*9a747e4fSDavid du Colombier 		}
479*9a747e4fSDavid du Colombier 		fmod = FWRITE;
480*9a747e4fSDavid du Colombier 		break;
481*9a747e4fSDavid du Colombier 
482*9a747e4fSDavid du Colombier 	case MBOTH:
483*9a747e4fSDavid du Colombier 		if((d->mode & DDIR) ||
484*9a747e4fSDavid du Colombier 		   (iaccess(f, d, DREAD) && !writeallow) ||
485*9a747e4fSDavid du Colombier 		   (iaccess(f, d, DWRITE) && !writeallow))
486*9a747e4fSDavid du Colombier 			goto badaccess;
487*9a747e4fSDavid du Colombier 		if(ro) {
488*9a747e4fSDavid du Colombier 			ou->err = Eronly;
489*9a747e4fSDavid du Colombier 			goto out;
490*9a747e4fSDavid du Colombier 		}
491*9a747e4fSDavid du Colombier 		fmod = FREAD+FWRITE;
492*9a747e4fSDavid du Colombier 		break;
493*9a747e4fSDavid du Colombier 
494*9a747e4fSDavid du Colombier 	case MEXEC:
495*9a747e4fSDavid du Colombier 		if((d->mode & DDIR) ||
496*9a747e4fSDavid du Colombier 		   iaccess(f, d, DEXEC))
497*9a747e4fSDavid du Colombier 			goto badaccess;
498*9a747e4fSDavid du Colombier 		fmod = FREAD;
499*9a747e4fSDavid du Colombier 		break;
500*9a747e4fSDavid du Colombier 
501*9a747e4fSDavid du Colombier 	default:
502*9a747e4fSDavid du Colombier 		ou->err = Emode;
503*9a747e4fSDavid du Colombier 		goto out;
504*9a747e4fSDavid du Colombier 	}
505*9a747e4fSDavid du Colombier 	if(in->mode & MTRUNC) {
506*9a747e4fSDavid du Colombier 		if((d->mode & DDIR) ||
507*9a747e4fSDavid du Colombier 		   (iaccess(f, d, DWRITE) && !writeallow))
508*9a747e4fSDavid du Colombier 			goto badaccess;
509*9a747e4fSDavid du Colombier 		if(ro) {
510*9a747e4fSDavid du Colombier 			ou->err = Eronly;
511*9a747e4fSDavid du Colombier 			goto out;
512*9a747e4fSDavid du Colombier 		}
513*9a747e4fSDavid du Colombier 	}
514*9a747e4fSDavid du Colombier 	t = 0;
515*9a747e4fSDavid du Colombier 	if(d->mode & DLOCK) {
516*9a747e4fSDavid du Colombier 		t = tlocked(p, d);
517*9a747e4fSDavid du Colombier 		if(t == 0) {
518*9a747e4fSDavid du Colombier 			ou->err = Elocked;
519*9a747e4fSDavid du Colombier 			goto out;
520*9a747e4fSDavid du Colombier 		}
521*9a747e4fSDavid du Colombier 		t->file = f;
522*9a747e4fSDavid du Colombier 	}
523*9a747e4fSDavid du Colombier 	if(in->mode & MRCLOSE)
524*9a747e4fSDavid du Colombier 		fmod |= FREMOV;
525*9a747e4fSDavid du Colombier 	f->open = fmod;
526*9a747e4fSDavid du Colombier 	if(in->mode & MTRUNC)
527*9a747e4fSDavid du Colombier 		if(!(d->mode & DAPND))
528*9a747e4fSDavid du Colombier 			dtrunc(p, d);
529*9a747e4fSDavid du Colombier 	f->tlock = t;
530*9a747e4fSDavid du Colombier 	f->lastra = 0;
531*9a747e4fSDavid du Colombier 	mkqid9p1(&ou->qid, &qid);
532*9a747e4fSDavid du Colombier 	goto out;
533*9a747e4fSDavid du Colombier 
534*9a747e4fSDavid du Colombier badaccess:
535*9a747e4fSDavid du Colombier 	ou->err = Eaccess;
536*9a747e4fSDavid du Colombier 	f->open = 0;
537*9a747e4fSDavid du Colombier 
538*9a747e4fSDavid du Colombier out:
539*9a747e4fSDavid du Colombier 	if(p)
540*9a747e4fSDavid du Colombier 		putbuf(p);
541*9a747e4fSDavid du Colombier 	if(f)
542*9a747e4fSDavid du Colombier 		qunlock(f);
543*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
544*9a747e4fSDavid du Colombier }
545*9a747e4fSDavid du Colombier 
546*9a747e4fSDavid du Colombier void
547*9a747e4fSDavid du Colombier f_create(Chan *cp, Oldfcall *in, Oldfcall *ou)
548*9a747e4fSDavid du Colombier {
549*9a747e4fSDavid du Colombier 	Iobuf *p, *p1;
550*9a747e4fSDavid du Colombier 	Dentry *d, *d1;
551*9a747e4fSDavid du Colombier 	File *f;
552*9a747e4fSDavid du Colombier 	int slot, slot1, fmod;
553*9a747e4fSDavid du Colombier 	long addr, addr1, path;
554*9a747e4fSDavid du Colombier 	Qid qid;
555*9a747e4fSDavid du Colombier 	Tlock *t;
556*9a747e4fSDavid du Colombier 	Wpath *w;
557*9a747e4fSDavid du Colombier 
558*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
559*9a747e4fSDavid du Colombier 		print("c_create %d\n", cp->chan);
560*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
561*9a747e4fSDavid du Colombier 		print("	name = %s\n", in->name);
562*9a747e4fSDavid du Colombier 		print("	perm = %lx+%lo\n", (in->perm>>28)&0xf,
563*9a747e4fSDavid du Colombier 				in->perm&0777);
564*9a747e4fSDavid du Colombier 		print("	mode = %d\n", in->mode);
565*9a747e4fSDavid du Colombier 	}
566*9a747e4fSDavid du Colombier 
567*9a747e4fSDavid du Colombier 	p = 0;
568*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
569*9a747e4fSDavid du Colombier 	if(!f) {
570*9a747e4fSDavid du Colombier 		ou->err = Efid;
571*9a747e4fSDavid du Colombier 		goto out;
572*9a747e4fSDavid du Colombier 	}
573*9a747e4fSDavid du Colombier 	if(isro(f->fs->dev)) {
574*9a747e4fSDavid du Colombier 		ou->err = Eronly;
575*9a747e4fSDavid du Colombier 		goto out;
576*9a747e4fSDavid du Colombier 	}
577*9a747e4fSDavid du Colombier 
578*9a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
579*9a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
580*9a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
581*9a747e4fSDavid du Colombier 		ou->err = Ealloc;
582*9a747e4fSDavid du Colombier 		goto out;
583*9a747e4fSDavid du Colombier 	}
584*9a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
585*9a747e4fSDavid du Colombier 		goto out;
586*9a747e4fSDavid du Colombier 	if(!(d->mode & DDIR)) {
587*9a747e4fSDavid du Colombier 		ou->err = Edir2;
588*9a747e4fSDavid du Colombier 		goto out;
589*9a747e4fSDavid du Colombier 	}
590*9a747e4fSDavid du Colombier 	if(cp != cons.chan && iaccess(f, d, DWRITE) && !writeallow) {
591*9a747e4fSDavid du Colombier 		ou->err = Eaccess;
592*9a747e4fSDavid du Colombier 		goto out;
593*9a747e4fSDavid du Colombier 	}
594*9a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
595*9a747e4fSDavid du Colombier 	if(!strncmp(in->name, ".", sizeof(in->name)) ||
596*9a747e4fSDavid du Colombier 	   !strncmp(in->name, "..", sizeof(in->name))) {
597*9a747e4fSDavid du Colombier 		ou->err = Edot;
598*9a747e4fSDavid du Colombier 		goto out;
599*9a747e4fSDavid du Colombier 	}
600*9a747e4fSDavid du Colombier 	if(checkname(in->name)) {
601*9a747e4fSDavid du Colombier 		ou->err = Ename;
602*9a747e4fSDavid du Colombier 		goto out;
603*9a747e4fSDavid du Colombier 	}
604*9a747e4fSDavid du Colombier 	addr1 = 0;
605*9a747e4fSDavid du Colombier 	slot1 = 0;	/* set */
606*9a747e4fSDavid du Colombier 	for(addr=0;; addr++) {
607*9a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0);
608*9a747e4fSDavid du Colombier 		if(!p1) {
609*9a747e4fSDavid du Colombier 			if(addr1)
610*9a747e4fSDavid du Colombier 				break;
611*9a747e4fSDavid du Colombier 			p1 = dnodebuf(p, d, addr, Tdir);
612*9a747e4fSDavid du Colombier 		}
613*9a747e4fSDavid du Colombier 		if(p1 == 0) {
614*9a747e4fSDavid du Colombier 			ou->err = Efull;
615*9a747e4fSDavid du Colombier 			goto out;
616*9a747e4fSDavid du Colombier 		}
617*9a747e4fSDavid du Colombier 		if(checktag(p1, Tdir, d->qid.path)) {
618*9a747e4fSDavid du Colombier 			putbuf(p1);
619*9a747e4fSDavid du Colombier 			goto phase;
620*9a747e4fSDavid du Colombier 		}
621*9a747e4fSDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
622*9a747e4fSDavid du Colombier 			d1 = getdir(p1, slot);
623*9a747e4fSDavid du Colombier 			if(!(d1->mode & DALLOC)) {
624*9a747e4fSDavid du Colombier 				if(!addr1) {
625*9a747e4fSDavid du Colombier 					addr1 = p1->addr;
626*9a747e4fSDavid du Colombier 					slot1 = slot + addr*DIRPERBUF;
627*9a747e4fSDavid du Colombier 				}
628*9a747e4fSDavid du Colombier 				continue;
629*9a747e4fSDavid du Colombier 			}
630*9a747e4fSDavid du Colombier 			if(!strncmp(in->name, d1->name, sizeof(in->name))) {
631*9a747e4fSDavid du Colombier 				putbuf(p1);
632*9a747e4fSDavid du Colombier 				ou->err = Eexist;
633*9a747e4fSDavid du Colombier 				goto out;
634*9a747e4fSDavid du Colombier 			}
635*9a747e4fSDavid du Colombier 		}
636*9a747e4fSDavid du Colombier 		putbuf(p1);
637*9a747e4fSDavid du Colombier 	}
638*9a747e4fSDavid du Colombier 	switch(in->mode & 7) {
639*9a747e4fSDavid du Colombier 	case MEXEC:
640*9a747e4fSDavid du Colombier 	case MREAD:		/* seems only useful to make directories */
641*9a747e4fSDavid du Colombier 		fmod = FREAD;
642*9a747e4fSDavid du Colombier 		break;
643*9a747e4fSDavid du Colombier 
644*9a747e4fSDavid du Colombier 	case MWRITE:
645*9a747e4fSDavid du Colombier 		fmod = FWRITE;
646*9a747e4fSDavid du Colombier 		break;
647*9a747e4fSDavid du Colombier 
648*9a747e4fSDavid du Colombier 	case MBOTH:
649*9a747e4fSDavid du Colombier 		fmod = FREAD+FWRITE;
650*9a747e4fSDavid du Colombier 		break;
651*9a747e4fSDavid du Colombier 
652*9a747e4fSDavid du Colombier 	default:
653*9a747e4fSDavid du Colombier 		ou->err = Emode;
654*9a747e4fSDavid du Colombier 		goto out;
655*9a747e4fSDavid du Colombier 	}
656*9a747e4fSDavid du Colombier 	if(in->perm & PDIR)
657*9a747e4fSDavid du Colombier 		if((in->mode & MTRUNC) || (in->perm & PAPND) || (fmod & FWRITE))
658*9a747e4fSDavid du Colombier 			goto badaccess;
659*9a747e4fSDavid du Colombier 	/*
660*9a747e4fSDavid du Colombier 	 * do it
661*9a747e4fSDavid du Colombier 	 */
662*9a747e4fSDavid du Colombier 	path = qidpathgen(&f->fs->dev);
663*9a747e4fSDavid du Colombier 	p1 = getbuf(f->fs->dev, addr1, Bread|Bimm|Bmod);
664*9a747e4fSDavid du Colombier 	d1 = getdir(p1, slot1);
665*9a747e4fSDavid du Colombier 	if(!d1 || checktag(p1, Tdir, d->qid.path)) {
666*9a747e4fSDavid du Colombier 		if(p1)
667*9a747e4fSDavid du Colombier 			putbuf(p1);
668*9a747e4fSDavid du Colombier 		goto phase;
669*9a747e4fSDavid du Colombier 	}
670*9a747e4fSDavid du Colombier 	if(d1->mode & DALLOC) {
671*9a747e4fSDavid du Colombier 		putbuf(p1);
672*9a747e4fSDavid du Colombier 		goto phase;
673*9a747e4fSDavid du Colombier 	}
674*9a747e4fSDavid du Colombier 
675*9a747e4fSDavid du Colombier 	strncpy(d1->name, in->name, sizeof(in->name));
676*9a747e4fSDavid du Colombier 	/*
677*9a747e4fSDavid du Colombier 	 * bogus argument passing -- see console.c
678*9a747e4fSDavid du Colombier 	 */
679*9a747e4fSDavid du Colombier 	if(cp == cons.chan) {
680*9a747e4fSDavid du Colombier 		d1->uid = cons.uid;
681*9a747e4fSDavid du Colombier 		d1->gid = cons.gid;
682*9a747e4fSDavid du Colombier 	} else {
683*9a747e4fSDavid du Colombier 		d1->uid = f->uid;
684*9a747e4fSDavid du Colombier 		d1->gid = d->gid;
685*9a747e4fSDavid du Colombier 		in->perm &= d->mode | ~0666;
686*9a747e4fSDavid du Colombier 		if(in->perm & PDIR)
687*9a747e4fSDavid du Colombier 			in->perm &= d->mode | ~0777;
688*9a747e4fSDavid du Colombier 	}
689*9a747e4fSDavid du Colombier 	d1->qid.path = path;
690*9a747e4fSDavid du Colombier 	d1->qid.version = 0;
691*9a747e4fSDavid du Colombier 	d1->mode = DALLOC | (in->perm & 0777);
692*9a747e4fSDavid du Colombier 	if(in->perm & PDIR) {
693*9a747e4fSDavid du Colombier 		d1->mode |= DDIR;
694*9a747e4fSDavid du Colombier 		d1->qid.path |= QPDIR;
695*9a747e4fSDavid du Colombier 	}
696*9a747e4fSDavid du Colombier 	if(in->perm & PAPND)
697*9a747e4fSDavid du Colombier 		d1->mode |= DAPND;
698*9a747e4fSDavid du Colombier 	t = 0;
699*9a747e4fSDavid du Colombier 	if(in->perm & PLOCK) {
700*9a747e4fSDavid du Colombier 		d1->mode |= DLOCK;
701*9a747e4fSDavid du Colombier 		t = tlocked(p1, d1);
702*9a747e4fSDavid du Colombier 	}
703*9a747e4fSDavid du Colombier 	accessdir(p1, d1, FWRITE);
704*9a747e4fSDavid du Colombier 	mkqid(&qid, d1, 0);
705*9a747e4fSDavid du Colombier 	putbuf(p1);
706*9a747e4fSDavid du Colombier 	accessdir(p, d, FWRITE);
707*9a747e4fSDavid du Colombier 
708*9a747e4fSDavid du Colombier 	/*
709*9a747e4fSDavid du Colombier 	 * do a walk to new directory entry
710*9a747e4fSDavid du Colombier 	 */
711*9a747e4fSDavid du Colombier 	w = newwp();
712*9a747e4fSDavid du Colombier 	if(!w) {
713*9a747e4fSDavid du Colombier 		ou->err = Ewalk;
714*9a747e4fSDavid du Colombier 		goto out;
715*9a747e4fSDavid du Colombier 	}
716*9a747e4fSDavid du Colombier 	w->addr = f->addr;
717*9a747e4fSDavid du Colombier 	w->slot = f->slot;
718*9a747e4fSDavid du Colombier 	w->up = f->wpath;
719*9a747e4fSDavid du Colombier 	f->wpath = w;
720*9a747e4fSDavid du Colombier 	f->qid = qid;
721*9a747e4fSDavid du Colombier 	f->tlock = t;
722*9a747e4fSDavid du Colombier 	f->lastra = 0;
723*9a747e4fSDavid du Colombier 	if(in->mode & MRCLOSE)
724*9a747e4fSDavid du Colombier 		fmod |= FREMOV;
725*9a747e4fSDavid du Colombier 	f->open = fmod;
726*9a747e4fSDavid du Colombier 	f->addr = addr1;
727*9a747e4fSDavid du Colombier 	f->slot = slot1;
728*9a747e4fSDavid du Colombier 	if(t)
729*9a747e4fSDavid du Colombier 		t->file = f;
730*9a747e4fSDavid du Colombier 	mkqid9p1(&ou->qid, &qid);
731*9a747e4fSDavid du Colombier 	goto out;
732*9a747e4fSDavid du Colombier 
733*9a747e4fSDavid du Colombier badaccess:
734*9a747e4fSDavid du Colombier 	ou->err = Eaccess;
735*9a747e4fSDavid du Colombier 	goto out;
736*9a747e4fSDavid du Colombier 
737*9a747e4fSDavid du Colombier phase:
738*9a747e4fSDavid du Colombier 	ou->err = Ephase;
739*9a747e4fSDavid du Colombier 
740*9a747e4fSDavid du Colombier out:
741*9a747e4fSDavid du Colombier 	if(p)
742*9a747e4fSDavid du Colombier 		putbuf(p);
743*9a747e4fSDavid du Colombier 	if(f)
744*9a747e4fSDavid du Colombier 		qunlock(f);
745*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
746*9a747e4fSDavid du Colombier }
747*9a747e4fSDavid du Colombier 
748*9a747e4fSDavid du Colombier void
749*9a747e4fSDavid du Colombier f_read(Chan *cp, Oldfcall *in, Oldfcall *ou)
750*9a747e4fSDavid du Colombier {
751*9a747e4fSDavid du Colombier 	Iobuf *p, *p1;
752*9a747e4fSDavid du Colombier 	File *f;
753*9a747e4fSDavid du Colombier 	Dentry *d, *d1;
754*9a747e4fSDavid du Colombier 	Tlock *t;
755*9a747e4fSDavid du Colombier 	long addr, offset, tim;
756*9a747e4fSDavid du Colombier 	int nread, count, n, o, slot;
757*9a747e4fSDavid du Colombier 
758*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
759*9a747e4fSDavid du Colombier 		print("c_read %d\n", cp->chan);
760*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
761*9a747e4fSDavid du Colombier 		print("	offset = %ld\n", in->offset);
762*9a747e4fSDavid du Colombier 		print("	count = %ld\n", in->count);
763*9a747e4fSDavid du Colombier 	}
764*9a747e4fSDavid du Colombier 
765*9a747e4fSDavid du Colombier 	p = 0;
766*9a747e4fSDavid du Colombier 	count = in->count;
767*9a747e4fSDavid du Colombier 	offset = in->offset;
768*9a747e4fSDavid du Colombier 	nread = 0;
769*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
770*9a747e4fSDavid du Colombier 	if(!f) {
771*9a747e4fSDavid du Colombier 		ou->err = Efid;
772*9a747e4fSDavid du Colombier 		goto out;
773*9a747e4fSDavid du Colombier 	}
774*9a747e4fSDavid du Colombier 	if(!(f->open & FREAD)) {
775*9a747e4fSDavid du Colombier 		ou->err = Eopen;
776*9a747e4fSDavid du Colombier 		goto out;
777*9a747e4fSDavid du Colombier 	}
778*9a747e4fSDavid du Colombier 	if(count < 0 || count > MAXDAT) {
779*9a747e4fSDavid du Colombier 		ou->err = Ecount;
780*9a747e4fSDavid du Colombier 		goto out;
781*9a747e4fSDavid du Colombier 	}
782*9a747e4fSDavid du Colombier 	if(offset < 0) {
783*9a747e4fSDavid du Colombier 		ou->err = Eoffset;
784*9a747e4fSDavid du Colombier 		goto out;
785*9a747e4fSDavid du Colombier 	}
786*9a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
787*9a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
788*9a747e4fSDavid du Colombier 	if(!d || !(d->mode & DALLOC)) {
789*9a747e4fSDavid du Colombier 		ou->err = Ealloc;
790*9a747e4fSDavid du Colombier 		goto out;
791*9a747e4fSDavid du Colombier 	}
792*9a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
793*9a747e4fSDavid du Colombier 		goto out;
794*9a747e4fSDavid du Colombier 	if(t = f->tlock) {
795*9a747e4fSDavid du Colombier 		tim = time(0);
796*9a747e4fSDavid du Colombier 		if(t->time < tim || t->file != f) {
797*9a747e4fSDavid du Colombier 			ou->err = Ebroken;
798*9a747e4fSDavid du Colombier 			goto out;
799*9a747e4fSDavid du Colombier 		}
800*9a747e4fSDavid du Colombier 		/* renew the lock */
801*9a747e4fSDavid du Colombier 		t->time = tim + TLOCK;
802*9a747e4fSDavid du Colombier 	}
803*9a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
804*9a747e4fSDavid du Colombier 	if(d->mode & DDIR) {
805*9a747e4fSDavid du Colombier 		addr = 0;
806*9a747e4fSDavid du Colombier 		goto dread;
807*9a747e4fSDavid du Colombier 	}
808*9a747e4fSDavid du Colombier 	if(offset+count > d->size)
809*9a747e4fSDavid du Colombier 		count = d->size - offset;
810*9a747e4fSDavid du Colombier 	while(count > 0) {
811*9a747e4fSDavid du Colombier 		addr = offset / BUFSIZE;
812*9a747e4fSDavid du Colombier 		if(addr == f->lastra+1)
813*9a747e4fSDavid du Colombier 			dbufread(p, d, addr+1);
814*9a747e4fSDavid du Colombier 		f->lastra = addr;
815*9a747e4fSDavid du Colombier 		o = offset % BUFSIZE;
816*9a747e4fSDavid du Colombier 		n = BUFSIZE - o;
817*9a747e4fSDavid du Colombier 		if(n > count)
818*9a747e4fSDavid du Colombier 			n = count;
819*9a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0);
820*9a747e4fSDavid du Colombier 		if(p1) {
821*9a747e4fSDavid du Colombier 			if(checktag(p1, Tfile, QPNONE)) {
822*9a747e4fSDavid du Colombier 				ou->err = Ephase;
823*9a747e4fSDavid du Colombier 				putbuf(p1);
824*9a747e4fSDavid du Colombier 				goto out;
825*9a747e4fSDavid du Colombier 			}
826*9a747e4fSDavid du Colombier 			memmove(ou->data+nread, p1->iobuf+o, n);
827*9a747e4fSDavid du Colombier 			putbuf(p1);
828*9a747e4fSDavid du Colombier 		} else
829*9a747e4fSDavid du Colombier 			memset(ou->data+nread, 0, n);
830*9a747e4fSDavid du Colombier 		count -= n;
831*9a747e4fSDavid du Colombier 		nread += n;
832*9a747e4fSDavid du Colombier 		offset += n;
833*9a747e4fSDavid du Colombier 	}
834*9a747e4fSDavid du Colombier 	goto out;
835*9a747e4fSDavid du Colombier 
836*9a747e4fSDavid du Colombier dread:
837*9a747e4fSDavid du Colombier 	p1 = dnodebuf(p, d, addr, 0);
838*9a747e4fSDavid du Colombier 	if(!p1)
839*9a747e4fSDavid du Colombier 		goto out;
840*9a747e4fSDavid du Colombier 	if(checktag(p1, Tdir, QPNONE)) {
841*9a747e4fSDavid du Colombier 		ou->err = Ephase;
842*9a747e4fSDavid du Colombier 		putbuf(p1);
843*9a747e4fSDavid du Colombier 		goto out;
844*9a747e4fSDavid du Colombier 	}
845*9a747e4fSDavid du Colombier 	n = DIRREC;
846*9a747e4fSDavid du Colombier 	for(slot=0; slot<DIRPERBUF; slot++) {
847*9a747e4fSDavid du Colombier 		d1 = getdir(p1, slot);
848*9a747e4fSDavid du Colombier 		if(!(d1->mode & DALLOC))
849*9a747e4fSDavid du Colombier 			continue;
850*9a747e4fSDavid du Colombier 		if(offset >= n) {
851*9a747e4fSDavid du Colombier 			offset -= n;
852*9a747e4fSDavid du Colombier 			continue;
853*9a747e4fSDavid du Colombier 		}
854*9a747e4fSDavid du Colombier 		if(count < n) {
855*9a747e4fSDavid du Colombier 			putbuf(p1);
856*9a747e4fSDavid du Colombier 			goto out;
857*9a747e4fSDavid du Colombier 		}
858*9a747e4fSDavid du Colombier 		if(convD2M9p1(d1, ou->data+nread) != n)
859*9a747e4fSDavid du Colombier 			print("dirread convD2M\n");
860*9a747e4fSDavid du Colombier 		nread += n;
861*9a747e4fSDavid du Colombier 		count -= n;
862*9a747e4fSDavid du Colombier 	}
863*9a747e4fSDavid du Colombier 	putbuf(p1);
864*9a747e4fSDavid du Colombier 	addr++;
865*9a747e4fSDavid du Colombier 	goto dread;
866*9a747e4fSDavid du Colombier 
867*9a747e4fSDavid du Colombier out:
868*9a747e4fSDavid du Colombier 	count = in->count - nread;
869*9a747e4fSDavid du Colombier 	if(count > 0)
870*9a747e4fSDavid du Colombier 		memset(ou->data+nread, 0, count);
871*9a747e4fSDavid du Colombier 	if(p)
872*9a747e4fSDavid du Colombier 		putbuf(p);
873*9a747e4fSDavid du Colombier 	if(f)
874*9a747e4fSDavid du Colombier 		qunlock(f);
875*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
876*9a747e4fSDavid du Colombier 	ou->count = nread;
877*9a747e4fSDavid du Colombier 	if(CHAT(cp))
878*9a747e4fSDavid du Colombier 		print("	nread = %d\n", nread);
879*9a747e4fSDavid du Colombier }
880*9a747e4fSDavid du Colombier 
881*9a747e4fSDavid du Colombier void
882*9a747e4fSDavid du Colombier f_write(Chan *cp, Oldfcall *in, Oldfcall *ou)
883*9a747e4fSDavid du Colombier {
884*9a747e4fSDavid du Colombier 	Iobuf *p, *p1;
885*9a747e4fSDavid du Colombier 	Dentry *d;
886*9a747e4fSDavid du Colombier 	File *f;
887*9a747e4fSDavid du Colombier 	Tlock *t;
888*9a747e4fSDavid du Colombier 	long offset, addr, tim;
889*9a747e4fSDavid du Colombier 	int count, nwrite, o, n;
890*9a747e4fSDavid du Colombier 
891*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
892*9a747e4fSDavid du Colombier 		print("c_write %d\n", cp->chan);
893*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
894*9a747e4fSDavid du Colombier 		print("	offset = %ld\n", in->offset);
895*9a747e4fSDavid du Colombier 		print("	count = %ld\n", in->count);
896*9a747e4fSDavid du Colombier 	}
897*9a747e4fSDavid du Colombier 
898*9a747e4fSDavid du Colombier 	offset = in->offset;
899*9a747e4fSDavid du Colombier 	count = in->count;
900*9a747e4fSDavid du Colombier 	nwrite = 0;
901*9a747e4fSDavid du Colombier 	p = 0;
902*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
903*9a747e4fSDavid du Colombier 	if(!f) {
904*9a747e4fSDavid du Colombier 		ou->err = Efid;
905*9a747e4fSDavid du Colombier 		goto out;
906*9a747e4fSDavid du Colombier 	}
907*9a747e4fSDavid du Colombier 	if(!(f->open & FWRITE)) {
908*9a747e4fSDavid du Colombier 		ou->err = Eopen;
909*9a747e4fSDavid du Colombier 		goto out;
910*9a747e4fSDavid du Colombier 	}
911*9a747e4fSDavid du Colombier 	if(isro(f->fs->dev)) {
912*9a747e4fSDavid du Colombier 		ou->err = Eronly;
913*9a747e4fSDavid du Colombier 		goto out;
914*9a747e4fSDavid du Colombier 	}
915*9a747e4fSDavid du Colombier 	if(count < 0 || count > MAXDAT) {
916*9a747e4fSDavid du Colombier 		ou->err = Ecount;
917*9a747e4fSDavid du Colombier 		goto out;
918*9a747e4fSDavid du Colombier 	}
919*9a747e4fSDavid du Colombier 	if(offset < 0) {
920*9a747e4fSDavid du Colombier 		ou->err = Eoffset;
921*9a747e4fSDavid du Colombier 		goto out;
922*9a747e4fSDavid du Colombier 	}
923*9a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread|Bmod);
924*9a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
925*9a747e4fSDavid du Colombier 	if(!d || !(d->mode & DALLOC)) {
926*9a747e4fSDavid du Colombier 		ou->err = Ealloc;
927*9a747e4fSDavid du Colombier 		goto out;
928*9a747e4fSDavid du Colombier 	}
929*9a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
930*9a747e4fSDavid du Colombier 		goto out;
931*9a747e4fSDavid du Colombier 	if(t = f->tlock) {
932*9a747e4fSDavid du Colombier 		tim = time(0);
933*9a747e4fSDavid du Colombier 		if(t->time < tim || t->file != f) {
934*9a747e4fSDavid du Colombier 			ou->err = Ebroken;
935*9a747e4fSDavid du Colombier 			goto out;
936*9a747e4fSDavid du Colombier 		}
937*9a747e4fSDavid du Colombier 		/* renew the lock */
938*9a747e4fSDavid du Colombier 		t->time = tim + TLOCK;
939*9a747e4fSDavid du Colombier 	}
940*9a747e4fSDavid du Colombier 	accessdir(p, d, FWRITE);
941*9a747e4fSDavid du Colombier 	if(d->mode & DAPND)
942*9a747e4fSDavid du Colombier 		offset = d->size;
943*9a747e4fSDavid du Colombier 	if(offset+count > d->size)
944*9a747e4fSDavid du Colombier 		d->size = offset+count;
945*9a747e4fSDavid du Colombier 	while(count > 0) {
946*9a747e4fSDavid du Colombier 		addr = offset / BUFSIZE;
947*9a747e4fSDavid du Colombier 		o = offset % BUFSIZE;
948*9a747e4fSDavid du Colombier 		n = BUFSIZE - o;
949*9a747e4fSDavid du Colombier 		if(n > count)
950*9a747e4fSDavid du Colombier 			n = count;
951*9a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, Tfile);
952*9a747e4fSDavid du Colombier 		if(p1 == 0) {
953*9a747e4fSDavid du Colombier 			ou->err = Efull;
954*9a747e4fSDavid du Colombier 			goto out;
955*9a747e4fSDavid du Colombier 		}
956*9a747e4fSDavid du Colombier 		if(checktag(p1, Tfile, d->qid.path)) {
957*9a747e4fSDavid du Colombier 			putbuf(p1);
958*9a747e4fSDavid du Colombier 			ou->err = Ephase;
959*9a747e4fSDavid du Colombier 			goto out;
960*9a747e4fSDavid du Colombier 		}
961*9a747e4fSDavid du Colombier 		memmove(p1->iobuf+o, in->data+nwrite, n);
962*9a747e4fSDavid du Colombier 		p1->flags |= Bmod;
963*9a747e4fSDavid du Colombier 		putbuf(p1);
964*9a747e4fSDavid du Colombier 		count -= n;
965*9a747e4fSDavid du Colombier 		nwrite += n;
966*9a747e4fSDavid du Colombier 		offset += n;
967*9a747e4fSDavid du Colombier 	}
968*9a747e4fSDavid du Colombier 	if(CHAT(cp))
969*9a747e4fSDavid du Colombier 		print("	nwrite = %d\n", nwrite);
970*9a747e4fSDavid du Colombier 
971*9a747e4fSDavid du Colombier out:
972*9a747e4fSDavid du Colombier 	if(p)
973*9a747e4fSDavid du Colombier 		putbuf(p);
974*9a747e4fSDavid du Colombier 	if(f)
975*9a747e4fSDavid du Colombier 		qunlock(f);
976*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
977*9a747e4fSDavid du Colombier 	ou->count = nwrite;
978*9a747e4fSDavid du Colombier }
979*9a747e4fSDavid du Colombier 
980*9a747e4fSDavid du Colombier int
981*9a747e4fSDavid du Colombier doremove(File *f, int iscon)
982*9a747e4fSDavid du Colombier {
983*9a747e4fSDavid du Colombier 	Iobuf *p, *p1;
984*9a747e4fSDavid du Colombier 	Dentry *d, *d1;
985*9a747e4fSDavid du Colombier 	long addr;
986*9a747e4fSDavid du Colombier 	int slot, err;
987*9a747e4fSDavid du Colombier 
988*9a747e4fSDavid du Colombier 	p = 0;
989*9a747e4fSDavid du Colombier 	p1 = 0;
990*9a747e4fSDavid du Colombier 	if(isro(f->fs->dev)) {
991*9a747e4fSDavid du Colombier 		err = Eronly;
992*9a747e4fSDavid du Colombier 		goto out;
993*9a747e4fSDavid du Colombier 	}
994*9a747e4fSDavid du Colombier 	/*
995*9a747e4fSDavid du Colombier 	 * check on parent directory of file to be deleted
996*9a747e4fSDavid du Colombier 	 */
997*9a747e4fSDavid du Colombier 	if(f->wpath == 0 || f->wpath->addr == f->addr) {
998*9a747e4fSDavid du Colombier 		err = Ephase;
999*9a747e4fSDavid du Colombier 		goto out;
1000*9a747e4fSDavid du Colombier 	}
1001*9a747e4fSDavid du Colombier 	p1 = getbuf(f->fs->dev, f->wpath->addr, Bread);
1002*9a747e4fSDavid du Colombier 	d1 = getdir(p1, f->wpath->slot);
1003*9a747e4fSDavid du Colombier 	if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
1004*9a747e4fSDavid du Colombier 		err = Ephase;
1005*9a747e4fSDavid du Colombier 		goto out;
1006*9a747e4fSDavid du Colombier 	}
1007*9a747e4fSDavid du Colombier 	if(!iscon && iaccess(f, d1, DWRITE)) {
1008*9a747e4fSDavid du Colombier 		err = Eaccess;
1009*9a747e4fSDavid du Colombier 		goto out;
1010*9a747e4fSDavid du Colombier 	}
1011*9a747e4fSDavid du Colombier 	accessdir(p1, d1, FWRITE);
1012*9a747e4fSDavid du Colombier 	putbuf(p1);
1013*9a747e4fSDavid du Colombier 	p1 = 0;
1014*9a747e4fSDavid du Colombier 
1015*9a747e4fSDavid du Colombier 	/*
1016*9a747e4fSDavid du Colombier 	 * check on file to be deleted
1017*9a747e4fSDavid du Colombier 	 */
1018*9a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
1019*9a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
1020*9a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1021*9a747e4fSDavid du Colombier 		err = Ealloc;
1022*9a747e4fSDavid du Colombier 		goto out;
1023*9a747e4fSDavid du Colombier 	}
1024*9a747e4fSDavid du Colombier 	if(err = mkqidcmp(&f->qid, d))
1025*9a747e4fSDavid du Colombier 		goto out;
1026*9a747e4fSDavid du Colombier 
1027*9a747e4fSDavid du Colombier 	/*
1028*9a747e4fSDavid du Colombier 	 * if deleting a directory, make sure it is empty
1029*9a747e4fSDavid du Colombier 	 */
1030*9a747e4fSDavid du Colombier 	if((d->mode & DDIR))
1031*9a747e4fSDavid du Colombier 	for(addr=0;; addr++) {
1032*9a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0);
1033*9a747e4fSDavid du Colombier 		if(!p1)
1034*9a747e4fSDavid du Colombier 			break;
1035*9a747e4fSDavid du Colombier 		if(checktag(p1, Tdir, d->qid.path)) {
1036*9a747e4fSDavid du Colombier 			err = Ephase;
1037*9a747e4fSDavid du Colombier 			goto out;
1038*9a747e4fSDavid du Colombier 		}
1039*9a747e4fSDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
1040*9a747e4fSDavid du Colombier 			d1 = getdir(p1, slot);
1041*9a747e4fSDavid du Colombier 			if(!(d1->mode & DALLOC))
1042*9a747e4fSDavid du Colombier 				continue;
1043*9a747e4fSDavid du Colombier 			err = Eempty;
1044*9a747e4fSDavid du Colombier 			goto out;
1045*9a747e4fSDavid du Colombier 		}
1046*9a747e4fSDavid du Colombier 		putbuf(p1);
1047*9a747e4fSDavid du Colombier 	}
1048*9a747e4fSDavid du Colombier 
1049*9a747e4fSDavid du Colombier 	/*
1050*9a747e4fSDavid du Colombier 	 * do it
1051*9a747e4fSDavid du Colombier 	 */
1052*9a747e4fSDavid du Colombier 	dtrunc(p, d);
1053*9a747e4fSDavid du Colombier 	memset(d, 0, sizeof(Dentry));
1054*9a747e4fSDavid du Colombier 	settag(p, Tdir, QPNONE);
1055*9a747e4fSDavid du Colombier 
1056*9a747e4fSDavid du Colombier out:
1057*9a747e4fSDavid du Colombier 	if(p1)
1058*9a747e4fSDavid du Colombier 		putbuf(p1);
1059*9a747e4fSDavid du Colombier 	if(p)
1060*9a747e4fSDavid du Colombier 		putbuf(p);
1061*9a747e4fSDavid du Colombier 	return err;
1062*9a747e4fSDavid du Colombier }
1063*9a747e4fSDavid du Colombier 
1064*9a747e4fSDavid du Colombier void
1065*9a747e4fSDavid du Colombier f_remove(Chan *cp, Oldfcall *in, Oldfcall *ou)
1066*9a747e4fSDavid du Colombier {
1067*9a747e4fSDavid du Colombier 	File *f;
1068*9a747e4fSDavid du Colombier 
1069*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
1070*9a747e4fSDavid du Colombier 		print("c_remove %d\n", cp->chan);
1071*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
1072*9a747e4fSDavid du Colombier 	}
1073*9a747e4fSDavid du Colombier 
1074*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
1075*9a747e4fSDavid du Colombier 	if(!f) {
1076*9a747e4fSDavid du Colombier 		ou->err = Efid;
1077*9a747e4fSDavid du Colombier 		goto out;
1078*9a747e4fSDavid du Colombier 	}
1079*9a747e4fSDavid du Colombier 	ou->err = doremove(f, cp==cons.chan);
1080*9a747e4fSDavid du Colombier 
1081*9a747e4fSDavid du Colombier out:
1082*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
1083*9a747e4fSDavid du Colombier 	if(f)
1084*9a747e4fSDavid du Colombier 		qunlock(f);
1085*9a747e4fSDavid du Colombier }
1086*9a747e4fSDavid du Colombier 
1087*9a747e4fSDavid du Colombier void
1088*9a747e4fSDavid du Colombier f_stat(Chan *cp, Oldfcall *in, Oldfcall *ou)
1089*9a747e4fSDavid du Colombier {
1090*9a747e4fSDavid du Colombier 	Iobuf *p;
1091*9a747e4fSDavid du Colombier 	Dentry *d;
1092*9a747e4fSDavid du Colombier 	File *f;
1093*9a747e4fSDavid du Colombier 
1094*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
1095*9a747e4fSDavid du Colombier 		print("c_stat %d\n", cp->chan);
1096*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
1097*9a747e4fSDavid du Colombier 	}
1098*9a747e4fSDavid du Colombier 
1099*9a747e4fSDavid du Colombier 	p = 0;
1100*9a747e4fSDavid du Colombier 	memset(ou->stat, 0, sizeof(ou->stat));
1101*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
1102*9a747e4fSDavid du Colombier 	if(!f) {
1103*9a747e4fSDavid du Colombier 		ou->err = Efid;
1104*9a747e4fSDavid du Colombier 		goto out;
1105*9a747e4fSDavid du Colombier 	}
1106*9a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
1107*9a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
1108*9a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1109*9a747e4fSDavid du Colombier 		ou->err = Ealloc;
1110*9a747e4fSDavid du Colombier 		goto out;
1111*9a747e4fSDavid du Colombier 	}
1112*9a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
1113*9a747e4fSDavid du Colombier 		goto out;
1114*9a747e4fSDavid du Colombier 	if(d->qid.path == QPROOT)	/* stat of root gives time */
1115*9a747e4fSDavid du Colombier 		d->atime = time(0);
1116*9a747e4fSDavid du Colombier 	if(convD2M9p1(d, ou->stat) != DIRREC)
1117*9a747e4fSDavid du Colombier 		print("stat convD2M\n");
1118*9a747e4fSDavid du Colombier 
1119*9a747e4fSDavid du Colombier out:
1120*9a747e4fSDavid du Colombier 	if(p)
1121*9a747e4fSDavid du Colombier 		putbuf(p);
1122*9a747e4fSDavid du Colombier 	if(f)
1123*9a747e4fSDavid du Colombier 		qunlock(f);
1124*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
1125*9a747e4fSDavid du Colombier }
1126*9a747e4fSDavid du Colombier 
1127*9a747e4fSDavid du Colombier void
1128*9a747e4fSDavid du Colombier f_wstat(Chan *cp, Oldfcall *in, Oldfcall *ou)
1129*9a747e4fSDavid du Colombier {
1130*9a747e4fSDavid du Colombier 	Iobuf *p, *p1;
1131*9a747e4fSDavid du Colombier 	Dentry *d, *d1, xd;
1132*9a747e4fSDavid du Colombier 	File *f;
1133*9a747e4fSDavid du Colombier 	int slot;
1134*9a747e4fSDavid du Colombier 	long addr;
1135*9a747e4fSDavid du Colombier 
1136*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
1137*9a747e4fSDavid du Colombier 		print("c_wstat %d\n", cp->chan);
1138*9a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
1139*9a747e4fSDavid du Colombier 	}
1140*9a747e4fSDavid du Colombier 
1141*9a747e4fSDavid du Colombier 	p = 0;
1142*9a747e4fSDavid du Colombier 	p1 = 0;
1143*9a747e4fSDavid du Colombier 	d1 = 0;
1144*9a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
1145*9a747e4fSDavid du Colombier 	if(!f) {
1146*9a747e4fSDavid du Colombier 		ou->err = Efid;
1147*9a747e4fSDavid du Colombier 		goto out;
1148*9a747e4fSDavid du Colombier 	}
1149*9a747e4fSDavid du Colombier 	if(isro(f->fs->dev)) {
1150*9a747e4fSDavid du Colombier 		ou->err = Eronly;
1151*9a747e4fSDavid du Colombier 		goto out;
1152*9a747e4fSDavid du Colombier 	}
1153*9a747e4fSDavid du Colombier 
1154*9a747e4fSDavid du Colombier 	/*
1155*9a747e4fSDavid du Colombier 	 * first get parent
1156*9a747e4fSDavid du Colombier 	 */
1157*9a747e4fSDavid du Colombier 	if(f->wpath) {
1158*9a747e4fSDavid du Colombier 		p1 = getbuf(f->fs->dev, f->wpath->addr, Bread);
1159*9a747e4fSDavid du Colombier 		d1 = getdir(p1, f->wpath->slot);
1160*9a747e4fSDavid du Colombier 		if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
1161*9a747e4fSDavid du Colombier 			ou->err = Ephase;
1162*9a747e4fSDavid du Colombier 			goto out;
1163*9a747e4fSDavid du Colombier 		}
1164*9a747e4fSDavid du Colombier 	}
1165*9a747e4fSDavid du Colombier 
1166*9a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
1167*9a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
1168*9a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1169*9a747e4fSDavid du Colombier 		ou->err = Ealloc;
1170*9a747e4fSDavid du Colombier 		goto out;
1171*9a747e4fSDavid du Colombier 	}
1172*9a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
1173*9a747e4fSDavid du Colombier 		goto out;
1174*9a747e4fSDavid du Colombier 
1175*9a747e4fSDavid du Colombier 	convM2D9p1(in->stat, &xd);
1176*9a747e4fSDavid du Colombier 	if(CHAT(cp)) {
1177*9a747e4fSDavid du Colombier 		print("	d.name = %s\n", xd.name);
1178*9a747e4fSDavid du Colombier 		print("	d.uid  = %d\n", xd.uid);
1179*9a747e4fSDavid du Colombier 		print("	d.gid  = %d\n", xd.gid);
1180*9a747e4fSDavid du Colombier 		print("	d.mode = %.4x\n", xd.mode);
1181*9a747e4fSDavid du Colombier 	}
1182*9a747e4fSDavid du Colombier 
1183*9a747e4fSDavid du Colombier 	/*
1184*9a747e4fSDavid du Colombier 	 * if chown,
1185*9a747e4fSDavid du Colombier 	 * must be god
1186*9a747e4fSDavid du Colombier 	 */
1187*9a747e4fSDavid du Colombier 	while(xd.uid != d->uid) {
1188*9a747e4fSDavid du Colombier 		if(wstatallow)			/* set to allow chown during boot */
1189*9a747e4fSDavid du Colombier 			break;
1190*9a747e4fSDavid du Colombier 		ou->err = Enotu;
1191*9a747e4fSDavid du Colombier 		goto out;
1192*9a747e4fSDavid du Colombier 	}
1193*9a747e4fSDavid du Colombier 
1194*9a747e4fSDavid du Colombier 	/*
1195*9a747e4fSDavid du Colombier 	 * if chgroup,
1196*9a747e4fSDavid du Colombier 	 * must be either
1197*9a747e4fSDavid du Colombier 	 *	a) owner and in new group
1198*9a747e4fSDavid du Colombier 	 *	b) leader of both groups
1199*9a747e4fSDavid du Colombier 	 */
1200*9a747e4fSDavid du Colombier 	while(xd.gid != d->gid) {
1201*9a747e4fSDavid du Colombier 		if(wstatallow || writeallow)		/* set to allow chgrp during boot */
1202*9a747e4fSDavid du Colombier 			break;
1203*9a747e4fSDavid du Colombier 		if(d->uid == f->uid && ingroup(f->uid, xd.gid))
1204*9a747e4fSDavid du Colombier 			break;
1205*9a747e4fSDavid du Colombier 		if(leadgroup(f->uid, xd.gid))
1206*9a747e4fSDavid du Colombier 			if(leadgroup(f->uid, d->gid))
1207*9a747e4fSDavid du Colombier 				break;
1208*9a747e4fSDavid du Colombier 		ou->err = Enotg;
1209*9a747e4fSDavid du Colombier 		goto out;
1210*9a747e4fSDavid du Colombier 	}
1211*9a747e4fSDavid du Colombier 
1212*9a747e4fSDavid du Colombier 	/*
1213*9a747e4fSDavid du Colombier 	 * if rename,
1214*9a747e4fSDavid du Colombier 	 * must have write permission in parent
1215*9a747e4fSDavid du Colombier 	 */
1216*9a747e4fSDavid du Colombier 	if(xd.name[0] == 0)
1217*9a747e4fSDavid du Colombier 		strncpy(xd.name, d->name, sizeof(xd.name));
1218*9a747e4fSDavid du Colombier 	while(strncmp(d->name, xd.name, sizeof(d->name)) != 0) {
1219*9a747e4fSDavid du Colombier 		if(checkname(xd.name)) {
1220*9a747e4fSDavid du Colombier 			ou->err = Ename;
1221*9a747e4fSDavid du Colombier 			goto out;
1222*9a747e4fSDavid du Colombier 		}
1223*9a747e4fSDavid du Colombier 
1224*9a747e4fSDavid du Colombier 		if(strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
1225*9a747e4fSDavid du Colombier 			ou->err = Ename;
1226*9a747e4fSDavid du Colombier 			goto out;
1227*9a747e4fSDavid du Colombier 		}
1228*9a747e4fSDavid du Colombier 
1229*9a747e4fSDavid du Colombier 		/*
1230*9a747e4fSDavid du Colombier 		 * drop entry to prevent lock, then
1231*9a747e4fSDavid du Colombier 		 * check that destination name is unique,
1232*9a747e4fSDavid du Colombier 		 */
1233*9a747e4fSDavid du Colombier 		putbuf(p);
1234*9a747e4fSDavid du Colombier 		for(addr=0;; addr++) {
1235*9a747e4fSDavid du Colombier 			p = dnodebuf(p1, d1, addr, 0);
1236*9a747e4fSDavid du Colombier 			if(!p)
1237*9a747e4fSDavid du Colombier 				break;
1238*9a747e4fSDavid du Colombier 			if(checktag(p, Tdir, d1->qid.path)) {
1239*9a747e4fSDavid du Colombier 				putbuf(p);
1240*9a747e4fSDavid du Colombier 				continue;
1241*9a747e4fSDavid du Colombier 			}
1242*9a747e4fSDavid du Colombier 			for(slot=0; slot<DIRPERBUF; slot++) {
1243*9a747e4fSDavid du Colombier 				d = getdir(p, slot);
1244*9a747e4fSDavid du Colombier 				if(!(d->mode & DALLOC))
1245*9a747e4fSDavid du Colombier 					continue;
1246*9a747e4fSDavid du Colombier 				if(!strncmp(xd.name, d->name, sizeof(xd.name))) {
1247*9a747e4fSDavid du Colombier 					ou->err = Eexist;
1248*9a747e4fSDavid du Colombier 					goto out;
1249*9a747e4fSDavid du Colombier 				}
1250*9a747e4fSDavid du Colombier 			}
1251*9a747e4fSDavid du Colombier 			putbuf(p);
1252*9a747e4fSDavid du Colombier 		}
1253*9a747e4fSDavid du Colombier 
1254*9a747e4fSDavid du Colombier 		/*
1255*9a747e4fSDavid du Colombier 		 * reacquire entry
1256*9a747e4fSDavid du Colombier 		 */
1257*9a747e4fSDavid du Colombier 		p = getbuf(f->fs->dev, f->addr, Bread);
1258*9a747e4fSDavid du Colombier 		d = getdir(p, f->slot);
1259*9a747e4fSDavid du Colombier 		if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1260*9a747e4fSDavid du Colombier 			ou->err = Ephase;
1261*9a747e4fSDavid du Colombier 			goto out;
1262*9a747e4fSDavid du Colombier 		}
1263*9a747e4fSDavid du Colombier 
1264*9a747e4fSDavid du Colombier 		if(wstatallow || writeallow) /* set to allow rename during boot */
1265*9a747e4fSDavid du Colombier 			break;
1266*9a747e4fSDavid du Colombier 		if(!d1 || iaccess(f, d1, DWRITE)) {
1267*9a747e4fSDavid du Colombier 			ou->err = Eaccess;
1268*9a747e4fSDavid du Colombier 			goto out;
1269*9a747e4fSDavid du Colombier 		}
1270*9a747e4fSDavid du Colombier 		break;
1271*9a747e4fSDavid du Colombier 	}
1272*9a747e4fSDavid du Colombier 
1273*9a747e4fSDavid du Colombier 	/*
1274*9a747e4fSDavid du Colombier 	 * if mode/time, either
1275*9a747e4fSDavid du Colombier 	 *	a) owner
1276*9a747e4fSDavid du Colombier 	 *	b) leader of either group
1277*9a747e4fSDavid du Colombier 	 */
1278*9a747e4fSDavid du Colombier 	while(d->mtime != xd.mtime ||
1279*9a747e4fSDavid du Colombier 	     ((d->mode^xd.mode) & (DAPND|DLOCK|0777))) {
1280*9a747e4fSDavid du Colombier 		if(wstatallow)			/* set to allow chmod during boot */
1281*9a747e4fSDavid du Colombier 			break;
1282*9a747e4fSDavid du Colombier 		if(d->uid == f->uid)
1283*9a747e4fSDavid du Colombier 			break;
1284*9a747e4fSDavid du Colombier 		if(leadgroup(f->uid, xd.gid))
1285*9a747e4fSDavid du Colombier 			break;
1286*9a747e4fSDavid du Colombier 		if(leadgroup(f->uid, d->gid))
1287*9a747e4fSDavid du Colombier 			break;
1288*9a747e4fSDavid du Colombier 		ou->err = Enotu;
1289*9a747e4fSDavid du Colombier 		goto out;
1290*9a747e4fSDavid du Colombier 	}
1291*9a747e4fSDavid du Colombier 	d->mtime = xd.mtime;
1292*9a747e4fSDavid du Colombier 	d->uid = xd.uid;
1293*9a747e4fSDavid du Colombier 	d->gid = xd.gid;
1294*9a747e4fSDavid du Colombier 	d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
1295*9a747e4fSDavid du Colombier 
1296*9a747e4fSDavid du Colombier 	strncpy(d->name, xd.name, sizeof(d->name));
1297*9a747e4fSDavid du Colombier 	if(wstatallow) {
1298*9a747e4fSDavid du Colombier 		p->flags |= Bmod;
1299*9a747e4fSDavid du Colombier 		if(xd.atime)
1300*9a747e4fSDavid du Colombier 			d->atime = xd.atime;
1301*9a747e4fSDavid du Colombier 		if(xd.mtime)
1302*9a747e4fSDavid du Colombier 			d->mtime = xd.mtime;
1303*9a747e4fSDavid du Colombier 	} else
1304*9a747e4fSDavid du Colombier 		accessdir(p, d, FREAD);
1305*9a747e4fSDavid du Colombier 
1306*9a747e4fSDavid du Colombier out:
1307*9a747e4fSDavid du Colombier 	if(p)
1308*9a747e4fSDavid du Colombier 		putbuf(p);
1309*9a747e4fSDavid du Colombier 	if(p1)
1310*9a747e4fSDavid du Colombier 		putbuf(p1);
1311*9a747e4fSDavid du Colombier 	if(f)
1312*9a747e4fSDavid du Colombier 		qunlock(f);
1313*9a747e4fSDavid du Colombier 	ou->fid = in->fid;
1314*9a747e4fSDavid du Colombier }
1315*9a747e4fSDavid du Colombier 
1316*9a747e4fSDavid du Colombier void
1317*9a747e4fSDavid du Colombier (*call9p1[MAXSYSCALL])(Chan*, Oldfcall*, Oldfcall*) =
1318*9a747e4fSDavid du Colombier {
1319*9a747e4fSDavid du Colombier 	[Tnop9p1]		f_nop,
1320*9a747e4fSDavid du Colombier 	[Tosession9p1]	f_session,
1321*9a747e4fSDavid du Colombier 	[Tsession9p1]	f_session,
1322*9a747e4fSDavid du Colombier 	[Tflush9p1]	f_flush,
1323*9a747e4fSDavid du Colombier 	[Toattach9p1]	f_attach,
1324*9a747e4fSDavid du Colombier 	[Tattach9p1]	f_attach,
1325*9a747e4fSDavid du Colombier 	[Tclone9p1]	f_clone,
1326*9a747e4fSDavid du Colombier 	[Twalk9p1]		f_walk,
1327*9a747e4fSDavid du Colombier 	[Topen9p1]		f_open,
1328*9a747e4fSDavid du Colombier 	[Tcreate9p1]	f_create,
1329*9a747e4fSDavid du Colombier 	[Tread9p1]		f_read,
1330*9a747e4fSDavid du Colombier 	[Twrite9p1]	f_write,
1331*9a747e4fSDavid du Colombier 	[Tclunk9p1]	f_clunk,
1332*9a747e4fSDavid du Colombier 	[Tremove9p1]	f_remove,
1333*9a747e4fSDavid du Colombier 	[Tstat9p1]		f_stat,
1334*9a747e4fSDavid du Colombier 	[Twstat9p1]	f_wstat,
1335*9a747e4fSDavid du Colombier 	[Tclwalk9p1]	f_clwalk,
1336*9a747e4fSDavid du Colombier };
1337*9a747e4fSDavid du Colombier 
1338*9a747e4fSDavid du Colombier static void
1339*9a747e4fSDavid du Colombier send(Chan *c, uchar *buf, int n)
1340*9a747e4fSDavid du Colombier {
1341*9a747e4fSDavid du Colombier 	int fd, m;
1342*9a747e4fSDavid du Colombier 
1343*9a747e4fSDavid du Colombier 	fd = c->chan;
1344*9a747e4fSDavid du Colombier 	m = write(fd, buf, n);
1345*9a747e4fSDavid du Colombier 	if(m == n)
1346*9a747e4fSDavid du Colombier 		return;
1347*9a747e4fSDavid du Colombier 	panic("write failed");
1348*9a747e4fSDavid du Colombier }
1349*9a747e4fSDavid du Colombier 
1350*9a747e4fSDavid du Colombier void
1351*9a747e4fSDavid du Colombier error9p1(Chan *c, uchar *buf)
1352*9a747e4fSDavid du Colombier {
1353*9a747e4fSDavid du Colombier 	buf[0] = Rnop9p1;
1354*9a747e4fSDavid du Colombier 	buf[1] = ~0;
1355*9a747e4fSDavid du Colombier 	buf[2] = ~0;
1356*9a747e4fSDavid du Colombier 
1357*9a747e4fSDavid du Colombier 	send(c, buf, 3);
1358*9a747e4fSDavid du Colombier }
1359*9a747e4fSDavid du Colombier 
1360*9a747e4fSDavid du Colombier void
1361*9a747e4fSDavid du Colombier serve9p1(Chan *chan, uchar *ib, int nib)
1362*9a747e4fSDavid du Colombier {
1363*9a747e4fSDavid du Colombier 	int n, t;
1364*9a747e4fSDavid du Colombier 	uchar inbuf[MAXMSG+MAXDAT], outbuf[MAXMSG+MAXDAT];
1365*9a747e4fSDavid du Colombier 	Oldfcall fi, fo;
1366*9a747e4fSDavid du Colombier 
1367*9a747e4fSDavid du Colombier 	for(;;){
1368*9a747e4fSDavid du Colombier 		if(nib){
1369*9a747e4fSDavid du Colombier 			memmove(inbuf, ib, nib);
1370*9a747e4fSDavid du Colombier 			n = nib;
1371*9a747e4fSDavid du Colombier 			nib = 0;
1372*9a747e4fSDavid du Colombier 		}else
1373*9a747e4fSDavid du Colombier 			n = read(chan->chan, inbuf, sizeof inbuf);
1374*9a747e4fSDavid du Colombier 		if(chat)
1375*9a747e4fSDavid du Colombier 			print("read msg %d\n", n);
1376*9a747e4fSDavid du Colombier 		if(n == 0 && (chan == cons.srvchan || chan == cons.chan))
1377*9a747e4fSDavid du Colombier 			continue;
1378*9a747e4fSDavid du Colombier 		if(n <= 0)
1379*9a747e4fSDavid du Colombier 			return;
1380*9a747e4fSDavid du Colombier 		if(convM2S9p1(inbuf, &fi, n) != n){
1381*9a747e4fSDavid du Colombier 			error9p1(chan, outbuf);
1382*9a747e4fSDavid du Colombier 			continue;
1383*9a747e4fSDavid du Colombier 		}
1384*9a747e4fSDavid du Colombier 
1385*9a747e4fSDavid du Colombier 		t = fi.type;
1386*9a747e4fSDavid du Colombier 		if(t < 0 || t >= MAXSYSCALL || (t&1) || !call9p1[t]) {
1387*9a747e4fSDavid du Colombier 			print("9p1: bad message type\n");
1388*9a747e4fSDavid du Colombier 			error9p1(chan, outbuf);
1389*9a747e4fSDavid du Colombier 			continue;
1390*9a747e4fSDavid du Colombier 		}
1391*9a747e4fSDavid du Colombier 
1392*9a747e4fSDavid du Colombier 		if(CHAT(chan))
1393*9a747e4fSDavid du Colombier 			print("9p1: fi %O\n", &fi);
1394*9a747e4fSDavid du Colombier 
1395*9a747e4fSDavid du Colombier 		/*
1396*9a747e4fSDavid du Colombier 		 * set up reply message
1397*9a747e4fSDavid du Colombier 		 */
1398*9a747e4fSDavid du Colombier 		fo.err = 0;
1399*9a747e4fSDavid du Colombier 		if(t == Tread9p1)
1400*9a747e4fSDavid du Colombier 			fo.data = (char*)outbuf + 8;
1401*9a747e4fSDavid du Colombier 
1402*9a747e4fSDavid du Colombier 		/*
1403*9a747e4fSDavid du Colombier 		 * call the file system
1404*9a747e4fSDavid du Colombier 		 */
1405*9a747e4fSDavid du Colombier 		cons.work.count++;
1406*9a747e4fSDavid du Colombier 		cons.rate.count += n;
1407*9a747e4fSDavid du Colombier 
1408*9a747e4fSDavid du Colombier 		/*
1409*9a747e4fSDavid du Colombier 		 * call the file system
1410*9a747e4fSDavid du Colombier 		 */
1411*9a747e4fSDavid du Colombier 		rlock(&mainlock);
1412*9a747e4fSDavid du Colombier 		rlock(&chan->reflock);
1413*9a747e4fSDavid du Colombier 
1414*9a747e4fSDavid du Colombier 		(*call9p1[t])(chan, &fi, &fo);
1415*9a747e4fSDavid du Colombier 
1416*9a747e4fSDavid du Colombier 		runlock(&chan->reflock);
1417*9a747e4fSDavid du Colombier 		runlock(&mainlock);
1418*9a747e4fSDavid du Colombier 
1419*9a747e4fSDavid du Colombier 		fo.type = t+1;
1420*9a747e4fSDavid du Colombier 		fo.tag = fi.tag;
1421*9a747e4fSDavid du Colombier 
1422*9a747e4fSDavid du Colombier 		if(chat)
1423*9a747e4fSDavid du Colombier 			print("9p1: fo %O\n", &fo);
1424*9a747e4fSDavid du Colombier 
1425*9a747e4fSDavid du Colombier 		if(fo.err) {
1426*9a747e4fSDavid du Colombier 			strcpy(fo.ename, errstring[fo.err]);
1427*9a747e4fSDavid du Colombier 			if(CHAT(cp))
1428*9a747e4fSDavid du Colombier 				print("	error: %s\n", fo.ename);
1429*9a747e4fSDavid du Colombier 			fo.type = Terror9p1+1;
1430*9a747e4fSDavid du Colombier 		}
1431*9a747e4fSDavid du Colombier 
1432*9a747e4fSDavid du Colombier 		n = convS2M9p1(&fo, outbuf);
1433*9a747e4fSDavid du Colombier 		if(n == 0) {
1434*9a747e4fSDavid du Colombier 			print("9p1: bad S2M conversion\n");
1435*9a747e4fSDavid du Colombier 			error9p1(chan, outbuf);
1436*9a747e4fSDavid du Colombier 			continue;
1437*9a747e4fSDavid du Colombier 		}
1438*9a747e4fSDavid du Colombier 
1439*9a747e4fSDavid du Colombier 		cons.rate.count += n;
1440*9a747e4fSDavid du Colombier 		send(chan, outbuf, n);
1441*9a747e4fSDavid du Colombier 	}
1442*9a747e4fSDavid du Colombier }
1443