xref: /plan9/sys/src/cmd/cwfs/9p1.c (revision 223a035810d484657ee1a815f68faa8211009d6d)
101a344a2SDavid du Colombier #include "all.h"
201a344a2SDavid du Colombier #include "9p1.h"
301a344a2SDavid du Colombier 
401a344a2SDavid du Colombier extern Nvrsafe	nvr;
501a344a2SDavid du Colombier 
601a344a2SDavid du Colombier typedef struct {
701a344a2SDavid du Colombier 	uchar	chal[CHALLEN];		/* locally generated challenge */
801a344a2SDavid du Colombier 	uchar	rchal[CHALLEN];		/* remotely generated challenge */
901a344a2SDavid du Colombier 	Lock	idlock;
1001a344a2SDavid du Colombier 	ulong	idoffset;		/* offset of id vector */
1101a344a2SDavid du Colombier 	ulong	idvec;			/* vector of acceptable id's */
1201a344a2SDavid du Colombier } Authinfo;
1301a344a2SDavid du Colombier 
1401a344a2SDavid du Colombier static void
f_nop(Chan * cp,Fcall *,Fcall *)1501a344a2SDavid du Colombier f_nop(Chan *cp, Fcall*, Fcall*)
1601a344a2SDavid du Colombier {
1701a344a2SDavid du Colombier 	if(CHAT(cp))
1801a344a2SDavid du Colombier 		print("c_nop %d\n", cp->chan);
1901a344a2SDavid du Colombier }
2001a344a2SDavid du Colombier 
2101a344a2SDavid du Colombier static void
f_flush(Chan * cp,Fcall *,Fcall *)2201a344a2SDavid du Colombier f_flush(Chan *cp, Fcall*, Fcall*)
2301a344a2SDavid du Colombier {
2401a344a2SDavid du Colombier 	if(CHAT(cp))
2501a344a2SDavid du Colombier 		print("c_flush %d\n", cp->chan);
2601a344a2SDavid du Colombier 	runlock(&cp->reflock);
2701a344a2SDavid du Colombier 	wlock(&cp->reflock);
2801a344a2SDavid du Colombier 	wunlock(&cp->reflock);
2901a344a2SDavid du Colombier 	rlock(&cp->reflock);
3001a344a2SDavid du Colombier }
3101a344a2SDavid du Colombier 
3201a344a2SDavid du Colombier /*
3301a344a2SDavid du Colombier  *  create a challenge for a fid space
3401a344a2SDavid du Colombier  */
3501a344a2SDavid du Colombier static void
mkchallenge(Authinfo * aip)3601a344a2SDavid du Colombier mkchallenge(Authinfo *aip)
3701a344a2SDavid du Colombier {
3801a344a2SDavid du Colombier 	int i;
3901a344a2SDavid du Colombier 
40*223a0358SDavid du Colombier 	srand((uintptr)aip + time(nil));
4101a344a2SDavid du Colombier 	for(i = 0; i < CHALLEN; i++)
4201a344a2SDavid du Colombier 		aip->chal[i] = nrand(256);
4301a344a2SDavid du Colombier 
4401a344a2SDavid du Colombier 	aip->idoffset = 0;
4501a344a2SDavid du Colombier 	aip->idvec = 0;
4601a344a2SDavid du Colombier }
4701a344a2SDavid du Colombier 
4801a344a2SDavid du Colombier static void
f_session(Chan * cp,Fcall * in,Fcall * ou)4901a344a2SDavid du Colombier f_session(Chan *cp, Fcall *in, Fcall *ou)
5001a344a2SDavid du Colombier {
5101a344a2SDavid du Colombier 	Authinfo *aip;
5201a344a2SDavid du Colombier 
5301a344a2SDavid du Colombier 	aip = (Authinfo*)cp->authinfo;
5401a344a2SDavid du Colombier 
5501a344a2SDavid du Colombier 	if(CHAT(cp))
5601a344a2SDavid du Colombier 		print("c_session %d\n", cp->chan);
5701a344a2SDavid du Colombier 	memmove(aip->rchal, in->chal, sizeof(aip->rchal));
5801a344a2SDavid du Colombier 	mkchallenge(aip);
5901a344a2SDavid du Colombier 	memmove(ou->chal, aip->chal, sizeof(ou->chal));
6001a344a2SDavid du Colombier 	if(noauth || wstatallow)
6101a344a2SDavid du Colombier 		memset(ou->authid, 0, sizeof(ou->authid));
6201a344a2SDavid du Colombier 	else
6301a344a2SDavid du Colombier 		memmove(ou->authid, nvr.authid, sizeof(ou->authid));
6401a344a2SDavid du Colombier 
6501a344a2SDavid du Colombier 	sprint(ou->authdom, "%s.%s", service, nvr.authdom);
6601a344a2SDavid du Colombier 	fileinit(cp);
6701a344a2SDavid du Colombier }
6801a344a2SDavid du Colombier 
6901a344a2SDavid du Colombier /*
7001a344a2SDavid du Colombier  *  match a challenge from an attach
7101a344a2SDavid du Colombier  */
7201a344a2SDavid du Colombier static int
authorize(Chan * cp,Fcall * in,Fcall * ou)7301a344a2SDavid du Colombier authorize(Chan *cp, Fcall *in, Fcall *ou)
7401a344a2SDavid du Colombier {
7501a344a2SDavid du Colombier 	Ticket t;
7601a344a2SDavid du Colombier 	Authenticator a;
7701a344a2SDavid du Colombier 	int x;
7801a344a2SDavid du Colombier 	ulong bit;
7901a344a2SDavid du Colombier 	Authinfo *aip;
8001a344a2SDavid du Colombier 
8101a344a2SDavid du Colombier 	if(noauth || wstatallow)	/* set to allow entry during boot */
8201a344a2SDavid du Colombier 		return 1;
8301a344a2SDavid du Colombier 
8401a344a2SDavid du Colombier 	if(strcmp(in->uname, "none") == 0)
8501a344a2SDavid du Colombier 		return 1;
8601a344a2SDavid du Colombier 
8701a344a2SDavid du Colombier 	if(in->type == Toattach)
8801a344a2SDavid du Colombier 		return 0;
8901a344a2SDavid du Colombier 
9001a344a2SDavid du Colombier 	/* decrypt and unpack ticket */
9101a344a2SDavid du Colombier 	convM2T9p1(in->ticket, &t, nvr.machkey);
9201a344a2SDavid du Colombier 	if(t.num != AuthTs){
9301a344a2SDavid du Colombier 		print("9p1: bad AuthTs num\n");
9401a344a2SDavid du Colombier 		return 0;
9501a344a2SDavid du Colombier 	}
9601a344a2SDavid du Colombier 
9701a344a2SDavid du Colombier 	/* decrypt and unpack authenticator */
9801a344a2SDavid du Colombier 	convM2A9p1(in->auth, &a, t.key);
9901a344a2SDavid du Colombier 	if(a.num != AuthAc){
10001a344a2SDavid du Colombier 		print("9p1: bad AuthAc num\n");
10101a344a2SDavid du Colombier 		return 0;
10201a344a2SDavid du Colombier 	}
10301a344a2SDavid du Colombier 
10401a344a2SDavid du Colombier 	/* challenges must match */
10501a344a2SDavid du Colombier 	aip = (Authinfo*)cp->authinfo;
10601a344a2SDavid du Colombier 	if(memcmp(a.chal, aip->chal, sizeof(a.chal)) != 0){
10701a344a2SDavid du Colombier 		print("9p1: bad challenge\n");
10801a344a2SDavid du Colombier 		return 0;
10901a344a2SDavid du Colombier 	}
11001a344a2SDavid du Colombier 
11101a344a2SDavid du Colombier 	/*
11201a344a2SDavid du Colombier 	 *  the id must be in a valid range.  the range is specified by a
11301a344a2SDavid du Colombier 	 *  lower bound (idoffset) and a bit vector (idvec) where a
11401a344a2SDavid du Colombier 	 *  bit set to 1 means unusable
11501a344a2SDavid du Colombier 	 */
11601a344a2SDavid du Colombier 	lock(&aip->idlock);
11701a344a2SDavid du Colombier 	x = a.id - aip->idoffset;
11801a344a2SDavid du Colombier 	bit = 1<<x;
11901a344a2SDavid du Colombier 	if(x < 0 || x > 31 || (bit&aip->idvec)){
12001a344a2SDavid du Colombier 		unlock(&aip->idlock);
12101a344a2SDavid du Colombier 		print("9p1: id out of range: idoff %ld idvec %lux id %ld\n",
12201a344a2SDavid du Colombier 		   aip->idoffset, aip->idvec, a.id);
12301a344a2SDavid du Colombier 		return 0;
12401a344a2SDavid du Colombier 	}
12501a344a2SDavid du Colombier 	aip->idvec |= bit;
12601a344a2SDavid du Colombier 
12701a344a2SDavid du Colombier 	/* normalize the vector */
12801a344a2SDavid du Colombier 	while(aip->idvec&0xffff0001){
12901a344a2SDavid du Colombier 		aip->idvec >>= 1;
13001a344a2SDavid du Colombier 		aip->idoffset++;
13101a344a2SDavid du Colombier 	}
13201a344a2SDavid du Colombier 	unlock(&aip->idlock);
13301a344a2SDavid du Colombier 
13401a344a2SDavid du Colombier 	/* ticket name and attach name must match */
13501a344a2SDavid du Colombier 	if(memcmp(in->uname, t.cuid, sizeof(in->uname)) != 0){
13601a344a2SDavid du Colombier 		print("9p1: names don't match\n");
13701a344a2SDavid du Colombier 		return 0;
13801a344a2SDavid du Colombier 	}
13901a344a2SDavid du Colombier 
14001a344a2SDavid du Colombier 	/* copy translated name into input record */
14101a344a2SDavid du Colombier 	memmove(in->uname, t.suid, sizeof(in->uname));
14201a344a2SDavid du Colombier 
14301a344a2SDavid du Colombier 	/* craft a reply */
14401a344a2SDavid du Colombier 	a.num = AuthAs;
14501a344a2SDavid du Colombier 	memmove(a.chal, aip->rchal, CHALLEN);
14601a344a2SDavid du Colombier 	convA2M9p1(&a, ou->rauth, t.key);
14701a344a2SDavid du Colombier 
14801a344a2SDavid du Colombier 	return 1;
14901a344a2SDavid du Colombier }
15001a344a2SDavid du Colombier 
15101a344a2SDavid du Colombier /*
15201a344a2SDavid du Colombier  * buggery to give false qid for
15301a344a2SDavid du Colombier  * the top 2 levels of the dump fs
15401a344a2SDavid du Colombier  */
15501a344a2SDavid du Colombier void
mkqid(Qid * qid,Dentry * d,int buggery)15601a344a2SDavid du Colombier mkqid(Qid* qid, Dentry *d, int buggery)
15701a344a2SDavid du Colombier {
15801a344a2SDavid du Colombier 	int c;
15901a344a2SDavid du Colombier 
16001a344a2SDavid du Colombier 	if(buggery && d->qid.path == (QPDIR|QPROOT)){
16101a344a2SDavid du Colombier 		c = d->name[0];
16201a344a2SDavid du Colombier 		if(isascii(c) && isdigit(c)){
16301a344a2SDavid du Colombier 			qid->path = 3;
16401a344a2SDavid du Colombier 			qid->vers = d->qid.version;
16501a344a2SDavid du Colombier 			qid->type = QTDIR;
16601a344a2SDavid du Colombier 
16701a344a2SDavid du Colombier 			c = (c-'0')*10 + (d->name[1]-'0');
16801a344a2SDavid du Colombier 			if(c >= 1 && c <= 12)
16901a344a2SDavid du Colombier 				qid->path = 4;
17001a344a2SDavid du Colombier 			return;
17101a344a2SDavid du Colombier 		}
17201a344a2SDavid du Colombier 	}
17301a344a2SDavid du Colombier 
17401a344a2SDavid du Colombier 	mkqid9p2(qid, &d->qid, d->mode);
17501a344a2SDavid du Colombier }
17601a344a2SDavid du Colombier 
17701a344a2SDavid du Colombier int
mkqidcmp(Qid * qid,Dentry * d)17801a344a2SDavid du Colombier mkqidcmp(Qid* qid, Dentry *d)
17901a344a2SDavid du Colombier {
18001a344a2SDavid du Colombier 	Qid tmp;
18101a344a2SDavid du Colombier 
18201a344a2SDavid du Colombier 	mkqid(&tmp, d, 1);
18301a344a2SDavid du Colombier 	if(qid->path == tmp.path && qid->type == tmp.type)
18401a344a2SDavid du Colombier 		return 0;
18501a344a2SDavid du Colombier 	return Eqid;
18601a344a2SDavid du Colombier }
18701a344a2SDavid du Colombier 
18801a344a2SDavid du Colombier static void
f_attach(Chan * cp,Fcall * in,Fcall * ou)18901a344a2SDavid du Colombier f_attach(Chan *cp, Fcall *in, Fcall *ou)
19001a344a2SDavid du Colombier {
19101a344a2SDavid du Colombier 	Iobuf *p;
19201a344a2SDavid du Colombier 	Dentry *d;
19301a344a2SDavid du Colombier 	File *f;
19401a344a2SDavid du Colombier 	int u;
19501a344a2SDavid du Colombier 	Filsys *fs;
19601a344a2SDavid du Colombier 	Off raddr;
19701a344a2SDavid du Colombier 
19801a344a2SDavid du Colombier 	if(CHAT(cp)) {
19901a344a2SDavid du Colombier 		print("c_attach %d\n", cp->chan);
20001a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
20101a344a2SDavid du Colombier 		print("\tuid = %s\n", in->uname);
20201a344a2SDavid du Colombier 		print("\targ = %s\n", in->aname);
20301a344a2SDavid du Colombier 	}
20401a344a2SDavid du Colombier 
20501a344a2SDavid du Colombier 	ou->qid = QID9P1(0,0);
20601a344a2SDavid du Colombier 	ou->fid = in->fid;
20701a344a2SDavid du Colombier 	if(!in->aname[0])	/* default */
20801a344a2SDavid du Colombier 		strncpy(in->aname, "main", sizeof(in->aname));
20901a344a2SDavid du Colombier 	p = 0;
21001a344a2SDavid du Colombier 	f = filep(cp, in->fid, 1);
21101a344a2SDavid du Colombier 	if(!f) {
21201a344a2SDavid du Colombier 		ou->err = Efid;
21301a344a2SDavid du Colombier 		goto out;
21401a344a2SDavid du Colombier 	}
21501a344a2SDavid du Colombier 
21601a344a2SDavid du Colombier 	u = -1;
21701a344a2SDavid du Colombier 	if(cp != cons.chan) {
21801a344a2SDavid du Colombier 		if(noattach && strcmp(in->uname, "none")) {
21901a344a2SDavid du Colombier 			ou->err = Enoattach;
22001a344a2SDavid du Colombier 			goto out;
22101a344a2SDavid du Colombier 		}
22201a344a2SDavid du Colombier 		if(authorize(cp, in, ou) == 0 || strcmp(in->uname, "adm") == 0) {
22301a344a2SDavid du Colombier 			ou->err = Eauth;
22401a344a2SDavid du Colombier 			goto out;
22501a344a2SDavid du Colombier 		}
22601a344a2SDavid du Colombier 		u = strtouid(in->uname);
22701a344a2SDavid du Colombier 		if(u < 0) {
22801a344a2SDavid du Colombier 			ou->err = Ebadu;
22901a344a2SDavid du Colombier 			goto out;
23001a344a2SDavid du Colombier 		}
23101a344a2SDavid du Colombier 	}
23201a344a2SDavid du Colombier 	f->uid = u;
23301a344a2SDavid du Colombier 
23401a344a2SDavid du Colombier 	fs = fsstr(in->aname);
23501a344a2SDavid du Colombier 	if(fs == 0) {
23601a344a2SDavid du Colombier 		ou->err = Ebadspc;
23701a344a2SDavid du Colombier 		goto out;
23801a344a2SDavid du Colombier 	}
23901a344a2SDavid du Colombier 	raddr = getraddr(fs->dev);
24001a344a2SDavid du Colombier 	p = getbuf(fs->dev, raddr, Brd);
24101a344a2SDavid du Colombier 	d = getdir(p, 0);
24201a344a2SDavid du Colombier 	if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) {
24301a344a2SDavid du Colombier 		ou->err = Ealloc;
24401a344a2SDavid du Colombier 		goto out;
24501a344a2SDavid du Colombier 	}
24601a344a2SDavid du Colombier 	if (iaccess(f, d, DEXEC) ||
24701a344a2SDavid du Colombier 	    f->uid == 0 && fs->dev->type == Devro) {
24801a344a2SDavid du Colombier 		/*
24901a344a2SDavid du Colombier 		 * 'none' not allowed on dump
25001a344a2SDavid du Colombier 		 */
25101a344a2SDavid du Colombier 		ou->err = Eaccess;
25201a344a2SDavid du Colombier 		goto out;
25301a344a2SDavid du Colombier 	}
25401a344a2SDavid du Colombier 	accessdir(p, d, FREAD, f->uid);
25501a344a2SDavid du Colombier 	mkqid(&f->qid, d, 1);
25601a344a2SDavid du Colombier 	f->fs = fs;
25701a344a2SDavid du Colombier 	f->addr = raddr;
25801a344a2SDavid du Colombier 	f->slot = 0;
25901a344a2SDavid du Colombier 	f->open = 0;
26001a344a2SDavid du Colombier 	freewp(f->wpath);
26101a344a2SDavid du Colombier 	f->wpath = 0;
26201a344a2SDavid du Colombier 
26301a344a2SDavid du Colombier 	mkqid9p1(&ou->qid, &f->qid);
26401a344a2SDavid du Colombier 
26501a344a2SDavid du Colombier 	strncpy(cp->whoname, in->uname, sizeof(cp->whoname));
26601a344a2SDavid du Colombier 	cp->whotime = time(nil);
26701a344a2SDavid du Colombier 	if(cons.flags & attachflag)
26801a344a2SDavid du Colombier 		print("9p1: attach %s %T to \"%s\" C%d\n",
26901a344a2SDavid du Colombier 			cp->whoname, cp->whotime, fs->name, cp->chan);
27001a344a2SDavid du Colombier 
27101a344a2SDavid du Colombier out:
27201a344a2SDavid du Colombier 	if((cons.flags & attachflag) && ou->err)
27301a344a2SDavid du Colombier 		print("9p1: attach %s %T SUCK EGGS --- %s\n",
27401a344a2SDavid du Colombier 			in->uname, time(nil), errstr9p[ou->err]);
27501a344a2SDavid du Colombier 	if(p)
27601a344a2SDavid du Colombier 		putbuf(p);
27701a344a2SDavid du Colombier 	if(f) {
27801a344a2SDavid du Colombier 		qunlock(f);
27901a344a2SDavid du Colombier 		if(ou->err)
28001a344a2SDavid du Colombier 			freefp(f);
28101a344a2SDavid du Colombier 	}
28201a344a2SDavid du Colombier }
28301a344a2SDavid du Colombier 
28401a344a2SDavid du Colombier static void
f_clone(Chan * cp,Fcall * in,Fcall * ou)28501a344a2SDavid du Colombier f_clone(Chan *cp, Fcall *in, Fcall *ou)
28601a344a2SDavid du Colombier {
28701a344a2SDavid du Colombier 	File *f1, *f2;
28801a344a2SDavid du Colombier 	Wpath *p;
28901a344a2SDavid du Colombier 	int fid, fid1;
29001a344a2SDavid du Colombier 
29101a344a2SDavid du Colombier 	if(CHAT(cp)) {
29201a344a2SDavid du Colombier 		print("c_clone %d\n", cp->chan);
29301a344a2SDavid du Colombier 		print("\told fid = %d\n", in->fid);
29401a344a2SDavid du Colombier 		print("\tnew fid = %d\n", in->newfid);
29501a344a2SDavid du Colombier 	}
29601a344a2SDavid du Colombier 
29701a344a2SDavid du Colombier 	fid = in->fid;
29801a344a2SDavid du Colombier 	fid1 = in->newfid;
29901a344a2SDavid du Colombier 
30001a344a2SDavid du Colombier 	f1 = 0;
30101a344a2SDavid du Colombier 	f2 = 0;
30201a344a2SDavid du Colombier 	if(fid < fid1) {
30301a344a2SDavid du Colombier 		f1 = filep(cp, fid, 0);
30401a344a2SDavid du Colombier 		f2 = filep(cp, fid1, 1);
30501a344a2SDavid du Colombier 	} else
30601a344a2SDavid du Colombier 	if(fid1 < fid) {
30701a344a2SDavid du Colombier 		f2 = filep(cp, fid1, 1);
30801a344a2SDavid du Colombier 		f1 = filep(cp, fid, 0);
30901a344a2SDavid du Colombier 	}
31001a344a2SDavid du Colombier 	if(!f1 || !f2) {
31101a344a2SDavid du Colombier 		ou->err = Efid;
31201a344a2SDavid du Colombier 		goto out;
31301a344a2SDavid du Colombier 	}
31401a344a2SDavid du Colombier 
31501a344a2SDavid du Colombier 
31601a344a2SDavid du Colombier 	f2->fs = f1->fs;
31701a344a2SDavid du Colombier 	f2->addr = f1->addr;
31801a344a2SDavid du Colombier 	f2->open = f1->open & ~FREMOV;
31901a344a2SDavid du Colombier 	f2->uid = f1->uid;
32001a344a2SDavid du Colombier 	f2->slot = f1->slot;
32101a344a2SDavid du Colombier 	f2->qid = f1->qid;
32201a344a2SDavid du Colombier 
32301a344a2SDavid du Colombier 	freewp(f2->wpath);
32401a344a2SDavid du Colombier 	lock(&wpathlock);
32501a344a2SDavid du Colombier 	f2->wpath = f1->wpath;
32601a344a2SDavid du Colombier 	for(p = f2->wpath; p; p = p->up)
32701a344a2SDavid du Colombier 		p->refs++;
32801a344a2SDavid du Colombier 	unlock(&wpathlock);
32901a344a2SDavid du Colombier 
33001a344a2SDavid du Colombier out:
33101a344a2SDavid du Colombier 	ou->fid = fid;
33201a344a2SDavid du Colombier 	if(f1)
33301a344a2SDavid du Colombier 		qunlock(f1);
33401a344a2SDavid du Colombier 	if(f2) {
33501a344a2SDavid du Colombier 		qunlock(f2);
33601a344a2SDavid du Colombier 		if(ou->err)
33701a344a2SDavid du Colombier 			freefp(f2);
33801a344a2SDavid du Colombier 	}
33901a344a2SDavid du Colombier }
34001a344a2SDavid du Colombier 
34101a344a2SDavid du Colombier static void
f_walk(Chan * cp,Fcall * in,Fcall * ou)34201a344a2SDavid du Colombier f_walk(Chan *cp, Fcall *in, Fcall *ou)
34301a344a2SDavid du Colombier {
34401a344a2SDavid du Colombier 	Iobuf *p, *p1;
34501a344a2SDavid du Colombier 	Dentry *d, *d1;
34601a344a2SDavid du Colombier 	File *f;
34701a344a2SDavid du Colombier 	Wpath *w;
34801a344a2SDavid du Colombier 	int slot;
34901a344a2SDavid du Colombier 	Off addr, qpath;
35001a344a2SDavid du Colombier 
35101a344a2SDavid du Colombier 	if(CHAT(cp)) {
35201a344a2SDavid du Colombier 		print("c_walk %d\n", cp->chan);
35301a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
35401a344a2SDavid du Colombier 		print("\tname = %s\n", in->name);
35501a344a2SDavid du Colombier 	}
35601a344a2SDavid du Colombier 
35701a344a2SDavid du Colombier 	ou->fid = in->fid;
35801a344a2SDavid du Colombier 	ou->qid = QID9P1(0,0);
35901a344a2SDavid du Colombier 	p = 0;
36001a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
36101a344a2SDavid du Colombier 	if(!f) {
36201a344a2SDavid du Colombier 		ou->err = Efid;
36301a344a2SDavid du Colombier 		goto out;
36401a344a2SDavid du Colombier 	}
36501a344a2SDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Brd);
36601a344a2SDavid du Colombier 	d = getdir(p, f->slot);
36701a344a2SDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
36801a344a2SDavid du Colombier 		ou->err = Ealloc;
36901a344a2SDavid du Colombier 		goto out;
37001a344a2SDavid du Colombier 	}
37101a344a2SDavid du Colombier 	if(!(d->mode & DDIR)) {
37201a344a2SDavid du Colombier 		ou->err = Edir1;
37301a344a2SDavid du Colombier 		goto out;
37401a344a2SDavid du Colombier 	}
37501a344a2SDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
37601a344a2SDavid du Colombier 		goto out;
37701a344a2SDavid du Colombier 	if(cp != cons.chan && iaccess(f, d, DEXEC)) {
37801a344a2SDavid du Colombier 		ou->err = Eaccess;
37901a344a2SDavid du Colombier 		goto out;
38001a344a2SDavid du Colombier 	}
38101a344a2SDavid du Colombier 	accessdir(p, d, FREAD, f->uid);
38201a344a2SDavid du Colombier 	if(strcmp(in->name, ".") == 0)
38301a344a2SDavid du Colombier 		goto setdot;
38401a344a2SDavid du Colombier 	if(strcmp(in->name, "..") == 0) {
38501a344a2SDavid du Colombier 		if(f->wpath == 0)
38601a344a2SDavid du Colombier 			goto setdot;
38701a344a2SDavid du Colombier 		putbuf(p);
38801a344a2SDavid du Colombier 		p = 0;
38901a344a2SDavid du Colombier 		addr = f->wpath->addr;
39001a344a2SDavid du Colombier 		slot = f->wpath->slot;
39101a344a2SDavid du Colombier 		p1 = getbuf(f->fs->dev, addr, Brd);
39201a344a2SDavid du Colombier 		d1 = getdir(p1, slot);
39301a344a2SDavid du Colombier 		if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
39401a344a2SDavid du Colombier 			if(p1)
39501a344a2SDavid du Colombier 				putbuf(p1);
39601a344a2SDavid du Colombier 			ou->err = Ephase;
39701a344a2SDavid du Colombier 			goto out;
39801a344a2SDavid du Colombier 		}
39901a344a2SDavid du Colombier 		lock(&wpathlock);
40001a344a2SDavid du Colombier 		f->wpath->refs--;
40101a344a2SDavid du Colombier 		f->wpath = f->wpath->up;
40201a344a2SDavid du Colombier 		unlock(&wpathlock);
40301a344a2SDavid du Colombier 		goto found;
40401a344a2SDavid du Colombier 	}
40501a344a2SDavid du Colombier 	for(addr=0;; addr++) {
40601a344a2SDavid du Colombier 		if(p == 0) {
40701a344a2SDavid du Colombier 			p = getbuf(f->fs->dev, f->addr, Brd);
40801a344a2SDavid du Colombier 			d = getdir(p, f->slot);
40901a344a2SDavid du Colombier 			if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
41001a344a2SDavid du Colombier 				ou->err = Ealloc;
41101a344a2SDavid du Colombier 				goto out;
41201a344a2SDavid du Colombier 			}
41301a344a2SDavid du Colombier 		}
41401a344a2SDavid du Colombier 		qpath = d->qid.path;
41501a344a2SDavid du Colombier 		p1 = dnodebuf1(p, d, addr, 0, f->uid);
41601a344a2SDavid du Colombier 		p = 0;
41701a344a2SDavid du Colombier 		if(!p1 || checktag(p1, Tdir, qpath) ) {
41801a344a2SDavid du Colombier 			if(p1)
41901a344a2SDavid du Colombier 				putbuf(p1);
42001a344a2SDavid du Colombier 			ou->err = Eentry;
42101a344a2SDavid du Colombier 			goto out;
42201a344a2SDavid du Colombier 		}
42301a344a2SDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
42401a344a2SDavid du Colombier 			d1 = getdir(p1, slot);
42501a344a2SDavid du Colombier 			if(!(d1->mode & DALLOC))
42601a344a2SDavid du Colombier 				continue;
42701a344a2SDavid du Colombier 			if(strncmp(in->name, d1->name, sizeof(in->name)) != 0)
42801a344a2SDavid du Colombier 				continue;
42901a344a2SDavid du Colombier 			/*
43001a344a2SDavid du Colombier 			 * update walk path
43101a344a2SDavid du Colombier 			 */
43201a344a2SDavid du Colombier 			w = newwp();
43301a344a2SDavid du Colombier 			if(!w) {
43401a344a2SDavid du Colombier 				ou->err = Ewalk;
43501a344a2SDavid du Colombier 				putbuf(p1);
43601a344a2SDavid du Colombier 				goto out;
43701a344a2SDavid du Colombier 			}
43801a344a2SDavid du Colombier 			w->addr = f->addr;
43901a344a2SDavid du Colombier 			w->slot = f->slot;
44001a344a2SDavid du Colombier 			w->up = f->wpath;
44101a344a2SDavid du Colombier 			f->wpath = w;
44201a344a2SDavid du Colombier 			slot += DIRPERBUF*addr;
44301a344a2SDavid du Colombier 			goto found;
44401a344a2SDavid du Colombier 		}
44501a344a2SDavid du Colombier 		putbuf(p1);
44601a344a2SDavid du Colombier 	}
44701a344a2SDavid du Colombier 
44801a344a2SDavid du Colombier found:
44901a344a2SDavid du Colombier 	f->addr = p1->addr;
45001a344a2SDavid du Colombier 	mkqid(&f->qid, d1, 1);
45101a344a2SDavid du Colombier 	putbuf(p1);
45201a344a2SDavid du Colombier 	f->slot = slot;
45301a344a2SDavid du Colombier 
45401a344a2SDavid du Colombier setdot:
45501a344a2SDavid du Colombier 	mkqid9p1(&ou->qid, &f->qid);
45601a344a2SDavid du Colombier 	f->open = 0;
45701a344a2SDavid du Colombier 
45801a344a2SDavid du Colombier out:
45901a344a2SDavid du Colombier 	if(p)
46001a344a2SDavid du Colombier 		putbuf(p);
46101a344a2SDavid du Colombier 	if(f)
46201a344a2SDavid du Colombier 		qunlock(f);
46301a344a2SDavid du Colombier }
46401a344a2SDavid du Colombier 
46501a344a2SDavid du Colombier static void
f_open(Chan * cp,Fcall * in,Fcall * ou)46601a344a2SDavid du Colombier f_open(Chan *cp, Fcall *in, Fcall *ou)
46701a344a2SDavid du Colombier {
46801a344a2SDavid du Colombier 	Iobuf *p;
46901a344a2SDavid du Colombier 	Dentry *d;
47001a344a2SDavid du Colombier 	File *f;
47101a344a2SDavid du Colombier 	Tlock *t;
47201a344a2SDavid du Colombier 	Qid qid;
47301a344a2SDavid du Colombier 	int ro, fmod, wok;
47401a344a2SDavid du Colombier 
47501a344a2SDavid du Colombier 	if(CHAT(cp)) {
47601a344a2SDavid du Colombier 		print("c_open %d\n", cp->chan);
47701a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
47801a344a2SDavid du Colombier 		print("\tmode = %o\n", in->mode);
47901a344a2SDavid du Colombier 	}
48001a344a2SDavid du Colombier 
48101a344a2SDavid du Colombier 	wok = 0;
48201a344a2SDavid du Colombier 	if(cp == cons.chan || writeallow)
48301a344a2SDavid du Colombier 		wok = 1;
48401a344a2SDavid du Colombier 
48501a344a2SDavid du Colombier 	p = 0;
48601a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
48701a344a2SDavid du Colombier 	if(!f) {
48801a344a2SDavid du Colombier 		ou->err = Efid;
48901a344a2SDavid du Colombier 		goto out;
49001a344a2SDavid du Colombier 	}
49101a344a2SDavid du Colombier 
49201a344a2SDavid du Colombier 	/*
49301a344a2SDavid du Colombier 	 * if remove on close, check access here
49401a344a2SDavid du Colombier 	 */
49501a344a2SDavid du Colombier 	ro = f->fs->dev->type == Devro;
49601a344a2SDavid du Colombier 	if(in->mode & ORCLOSE) {
49701a344a2SDavid du Colombier 		if(ro) {
49801a344a2SDavid du Colombier 			ou->err = Eronly;
49901a344a2SDavid du Colombier 			goto out;
50001a344a2SDavid du Colombier 		}
50101a344a2SDavid du Colombier 		/*
50201a344a2SDavid du Colombier 		 * check on parent directory of file to be deleted
50301a344a2SDavid du Colombier 		 */
50401a344a2SDavid du Colombier 		if(f->wpath == 0 || f->wpath->addr == f->addr) {
50501a344a2SDavid du Colombier 			ou->err = Ephase;
50601a344a2SDavid du Colombier 			goto out;
50701a344a2SDavid du Colombier 		}
50801a344a2SDavid du Colombier 		p = getbuf(f->fs->dev, f->wpath->addr, Brd);
50901a344a2SDavid du Colombier 		d = getdir(p, f->wpath->slot);
51001a344a2SDavid du Colombier 		if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
51101a344a2SDavid du Colombier 			ou->err = Ephase;
51201a344a2SDavid du Colombier 			goto out;
51301a344a2SDavid du Colombier 		}
51401a344a2SDavid du Colombier 		if(iaccess(f, d, DWRITE)) {
51501a344a2SDavid du Colombier 			ou->err = Eaccess;
51601a344a2SDavid du Colombier 			goto out;
51701a344a2SDavid du Colombier 		}
51801a344a2SDavid du Colombier 		putbuf(p);
51901a344a2SDavid du Colombier 	}
52001a344a2SDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Brd);
52101a344a2SDavid du Colombier 	d = getdir(p, f->slot);
52201a344a2SDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
52301a344a2SDavid du Colombier 		ou->err = Ealloc;
52401a344a2SDavid du Colombier 		goto out;
52501a344a2SDavid du Colombier 	}
52601a344a2SDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
52701a344a2SDavid du Colombier 		goto out;
52801a344a2SDavid du Colombier 	mkqid(&qid, d, 1);
52901a344a2SDavid du Colombier 	switch(in->mode & 7) {
53001a344a2SDavid du Colombier 
53101a344a2SDavid du Colombier 	case OREAD:
53201a344a2SDavid du Colombier 		if(iaccess(f, d, DREAD) && !wok)
53301a344a2SDavid du Colombier 			goto badaccess;
53401a344a2SDavid du Colombier 		fmod = FREAD;
53501a344a2SDavid du Colombier 		break;
53601a344a2SDavid du Colombier 
53701a344a2SDavid du Colombier 	case OWRITE:
53801a344a2SDavid du Colombier 		if((d->mode & DDIR) ||
53901a344a2SDavid du Colombier 		   (iaccess(f, d, DWRITE) && !wok))
54001a344a2SDavid du Colombier 			goto badaccess;
54101a344a2SDavid du Colombier 		if(ro) {
54201a344a2SDavid du Colombier 			ou->err = Eronly;
54301a344a2SDavid du Colombier 			goto out;
54401a344a2SDavid du Colombier 		}
54501a344a2SDavid du Colombier 		fmod = FWRITE;
54601a344a2SDavid du Colombier 		break;
54701a344a2SDavid du Colombier 
54801a344a2SDavid du Colombier 	case ORDWR:
54901a344a2SDavid du Colombier 		if((d->mode & DDIR) ||
55001a344a2SDavid du Colombier 		   (iaccess(f, d, DREAD) && !wok) ||
55101a344a2SDavid du Colombier 		   (iaccess(f, d, DWRITE) && !wok))
55201a344a2SDavid du Colombier 			goto badaccess;
55301a344a2SDavid du Colombier 		if(ro) {
55401a344a2SDavid du Colombier 			ou->err = Eronly;
55501a344a2SDavid du Colombier 			goto out;
55601a344a2SDavid du Colombier 		}
55701a344a2SDavid du Colombier 		fmod = FREAD+FWRITE;
55801a344a2SDavid du Colombier 		break;
55901a344a2SDavid du Colombier 
56001a344a2SDavid du Colombier 	case OEXEC:
56101a344a2SDavid du Colombier 		if((d->mode & DDIR) ||
56201a344a2SDavid du Colombier 		   (iaccess(f, d, DEXEC) && !wok))
56301a344a2SDavid du Colombier 			goto badaccess;
56401a344a2SDavid du Colombier 		fmod = FREAD;
56501a344a2SDavid du Colombier 		break;
56601a344a2SDavid du Colombier 
56701a344a2SDavid du Colombier 	default:
56801a344a2SDavid du Colombier 		ou->err = Emode;
56901a344a2SDavid du Colombier 		goto out;
57001a344a2SDavid du Colombier 	}
57101a344a2SDavid du Colombier 	if(in->mode & OTRUNC) {
57201a344a2SDavid du Colombier 		if((d->mode & DDIR) ||
57301a344a2SDavid du Colombier 		   (iaccess(f, d, DWRITE) && !wok))
57401a344a2SDavid du Colombier 			goto badaccess;
57501a344a2SDavid du Colombier 		if(ro) {
57601a344a2SDavid du Colombier 			ou->err = Eronly;
57701a344a2SDavid du Colombier 			goto out;
57801a344a2SDavid du Colombier 		}
57901a344a2SDavid du Colombier 	}
58001a344a2SDavid du Colombier 	t = 0;
58101a344a2SDavid du Colombier 	if(d->mode & DLOCK) {
58201a344a2SDavid du Colombier 		t = tlocked(p, d);
58301a344a2SDavid du Colombier 		if(t == nil) {
58401a344a2SDavid du Colombier 			ou->err = Elocked;
58501a344a2SDavid du Colombier 			goto out;
58601a344a2SDavid du Colombier 		}
58701a344a2SDavid du Colombier 	}
58801a344a2SDavid du Colombier 	if(in->mode & ORCLOSE)
58901a344a2SDavid du Colombier 		fmod |= FREMOV;
59001a344a2SDavid du Colombier 	f->open = fmod;
59101a344a2SDavid du Colombier 	if(in->mode & OTRUNC)
59201a344a2SDavid du Colombier 		if(!(d->mode & DAPND)) {
59301a344a2SDavid du Colombier 			dtrunc(p, d, f->uid);
59401a344a2SDavid du Colombier 			qid.vers = d->qid.version;
59501a344a2SDavid du Colombier 		}
59601a344a2SDavid du Colombier 	f->tlock = t;
59701a344a2SDavid du Colombier 	if(t)
59801a344a2SDavid du Colombier 		t->file = f;
59901a344a2SDavid du Colombier 	f->lastra = 1;
60001a344a2SDavid du Colombier 	mkqid9p1(&ou->qid, &qid);
60101a344a2SDavid du Colombier 	goto out;
60201a344a2SDavid du Colombier 
60301a344a2SDavid du Colombier badaccess:
60401a344a2SDavid du Colombier 	ou->err = Eaccess;
60501a344a2SDavid du Colombier 	f->open = 0;
60601a344a2SDavid du Colombier 
60701a344a2SDavid du Colombier out:
60801a344a2SDavid du Colombier 	if(p)
60901a344a2SDavid du Colombier 		putbuf(p);
61001a344a2SDavid du Colombier 	if(f)
61101a344a2SDavid du Colombier 		qunlock(f);
61201a344a2SDavid du Colombier 	ou->fid = in->fid;
61301a344a2SDavid du Colombier }
61401a344a2SDavid du Colombier 
61501a344a2SDavid du Colombier static void
f_create(Chan * cp,Fcall * in,Fcall * ou)61601a344a2SDavid du Colombier f_create(Chan *cp, Fcall *in, Fcall *ou)
61701a344a2SDavid du Colombier {
61801a344a2SDavid du Colombier 	Iobuf *p, *p1;
61901a344a2SDavid du Colombier 	Dentry *d, *d1;
62001a344a2SDavid du Colombier 	File *f;
62101a344a2SDavid du Colombier 	int slot, slot1, fmod, wok;
62201a344a2SDavid du Colombier 	Off addr, addr1, path;
62301a344a2SDavid du Colombier 	Qid qid;
62401a344a2SDavid du Colombier 	Tlock *t;
62501a344a2SDavid du Colombier 	Wpath *w;
62601a344a2SDavid du Colombier 
62701a344a2SDavid du Colombier 	if(CHAT(cp)) {
62801a344a2SDavid du Colombier 		print("c_create %d\n", cp->chan);
62901a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
63001a344a2SDavid du Colombier 		print("\tname = %s\n", in->name);
63101a344a2SDavid du Colombier 		print("\tperm = %lx+%lo\n", (in->perm>>28)&0xf,
63201a344a2SDavid du Colombier 				in->perm&0777);
63301a344a2SDavid du Colombier 		print("\tmode = %o\n", in->mode);
63401a344a2SDavid du Colombier 	}
63501a344a2SDavid du Colombier 
63601a344a2SDavid du Colombier 	wok = 0;
63701a344a2SDavid du Colombier 	if(cp == cons.chan || writeallow)
63801a344a2SDavid du Colombier 		wok = 1;
63901a344a2SDavid du Colombier 
64001a344a2SDavid du Colombier 	p = 0;
64101a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
64201a344a2SDavid du Colombier 	if(!f) {
64301a344a2SDavid du Colombier 		ou->err = Efid;
64401a344a2SDavid du Colombier 		goto out;
64501a344a2SDavid du Colombier 	}
64601a344a2SDavid du Colombier 	if(f->fs->dev->type == Devro) {
64701a344a2SDavid du Colombier 		ou->err = Eronly;
64801a344a2SDavid du Colombier 		goto out;
64901a344a2SDavid du Colombier 	}
65001a344a2SDavid du Colombier 
65101a344a2SDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Brd);
65201a344a2SDavid du Colombier 	d = getdir(p, f->slot);
65301a344a2SDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
65401a344a2SDavid du Colombier 		ou->err = Ealloc;
65501a344a2SDavid du Colombier 		goto out;
65601a344a2SDavid du Colombier 	}
65701a344a2SDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
65801a344a2SDavid du Colombier 		goto out;
65901a344a2SDavid du Colombier 	if(!(d->mode & DDIR)) {
66001a344a2SDavid du Colombier 		ou->err = Edir2;
66101a344a2SDavid du Colombier 		goto out;
66201a344a2SDavid du Colombier 	}
66301a344a2SDavid du Colombier 	if(iaccess(f, d, DWRITE) && !wok) {
66401a344a2SDavid du Colombier 		ou->err = Eaccess;
66501a344a2SDavid du Colombier 		goto out;
66601a344a2SDavid du Colombier 	}
66701a344a2SDavid du Colombier 	accessdir(p, d, FREAD, f->uid);
66801a344a2SDavid du Colombier 	if(!strncmp(in->name, ".", sizeof(in->name)) ||
66901a344a2SDavid du Colombier 	   !strncmp(in->name, "..", sizeof(in->name))) {
67001a344a2SDavid du Colombier 		ou->err = Edot;
67101a344a2SDavid du Colombier 		goto out;
67201a344a2SDavid du Colombier 	}
67301a344a2SDavid du Colombier 	if(checkname(in->name)) {
67401a344a2SDavid du Colombier 		ou->err = Ename;
67501a344a2SDavid du Colombier 		goto out;
67601a344a2SDavid du Colombier 	}
67701a344a2SDavid du Colombier 	addr1 = 0;
67801a344a2SDavid du Colombier 	slot1 = 0;	/* set */
67901a344a2SDavid du Colombier 	for(addr=0;; addr++) {
68001a344a2SDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0, f->uid);
68101a344a2SDavid du Colombier 		if(!p1) {
68201a344a2SDavid du Colombier 			if(addr1)
68301a344a2SDavid du Colombier 				break;
68401a344a2SDavid du Colombier 			p1 = dnodebuf(p, d, addr, Tdir, f->uid);
68501a344a2SDavid du Colombier 		}
68601a344a2SDavid du Colombier 		if(p1 == 0) {
68701a344a2SDavid du Colombier 			ou->err = Efull;
68801a344a2SDavid du Colombier 			goto out;
68901a344a2SDavid du Colombier 		}
69001a344a2SDavid du Colombier 		if(checktag(p1, Tdir, d->qid.path)) {
69101a344a2SDavid du Colombier 			putbuf(p1);
69201a344a2SDavid du Colombier 			goto phase;
69301a344a2SDavid du Colombier 		}
69401a344a2SDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
69501a344a2SDavid du Colombier 			d1 = getdir(p1, slot);
69601a344a2SDavid du Colombier 			if(!(d1->mode & DALLOC)) {
69701a344a2SDavid du Colombier 				if(!addr1) {
69801a344a2SDavid du Colombier 					addr1 = p1->addr;
69901a344a2SDavid du Colombier 					slot1 = slot + addr*DIRPERBUF;
70001a344a2SDavid du Colombier 				}
70101a344a2SDavid du Colombier 				continue;
70201a344a2SDavid du Colombier 			}
70301a344a2SDavid du Colombier 			if(!strncmp(in->name, d1->name, sizeof(in->name))) {
70401a344a2SDavid du Colombier 				putbuf(p1);
70501a344a2SDavid du Colombier 				ou->err = Eexist;
70601a344a2SDavid du Colombier 				goto out;
70701a344a2SDavid du Colombier 			}
70801a344a2SDavid du Colombier 		}
70901a344a2SDavid du Colombier 		putbuf(p1);
71001a344a2SDavid du Colombier 	}
71101a344a2SDavid du Colombier 	switch(in->mode & 7) {
71201a344a2SDavid du Colombier 	case OEXEC:
71301a344a2SDavid du Colombier 	case OREAD:		/* seems only useful to make directories */
71401a344a2SDavid du Colombier 		fmod = FREAD;
71501a344a2SDavid du Colombier 		break;
71601a344a2SDavid du Colombier 
71701a344a2SDavid du Colombier 	case OWRITE:
71801a344a2SDavid du Colombier 		fmod = FWRITE;
71901a344a2SDavid du Colombier 		break;
72001a344a2SDavid du Colombier 
72101a344a2SDavid du Colombier 	case ORDWR:
72201a344a2SDavid du Colombier 		fmod = FREAD+FWRITE;
72301a344a2SDavid du Colombier 		break;
72401a344a2SDavid du Colombier 
72501a344a2SDavid du Colombier 	default:
72601a344a2SDavid du Colombier 		ou->err = Emode;
72701a344a2SDavid du Colombier 		goto out;
72801a344a2SDavid du Colombier 	}
72901a344a2SDavid du Colombier 	if(in->perm & PDIR)
73001a344a2SDavid du Colombier 		if((in->mode & OTRUNC) || (in->perm & PAPND) || (fmod & FWRITE))
73101a344a2SDavid du Colombier 			goto badaccess;
73201a344a2SDavid du Colombier 	/*
73301a344a2SDavid du Colombier 	 * do it
73401a344a2SDavid du Colombier 	 */
73501a344a2SDavid du Colombier 	path = qidpathgen(f->fs->dev);
73601a344a2SDavid du Colombier 	p1 = getbuf(f->fs->dev, addr1, Brd|Bimm|Bmod);
73701a344a2SDavid du Colombier 	d1 = getdir(p1, slot1);
73801a344a2SDavid du Colombier 	if(!d1 || checktag(p1, Tdir, d->qid.path)) {
73901a344a2SDavid du Colombier 		if(p1)
74001a344a2SDavid du Colombier 			putbuf(p1);
74101a344a2SDavid du Colombier 		goto phase;
74201a344a2SDavid du Colombier 	}
74301a344a2SDavid du Colombier 	if(d1->mode & DALLOC) {
74401a344a2SDavid du Colombier 		putbuf(p1);
74501a344a2SDavid du Colombier 		goto phase;
74601a344a2SDavid du Colombier 	}
74701a344a2SDavid du Colombier 
74801a344a2SDavid du Colombier 	strncpy(d1->name, in->name, sizeof(in->name));
74901a344a2SDavid du Colombier 	if(cp == cons.chan) {
75001a344a2SDavid du Colombier 		d1->uid = cons.uid;
75101a344a2SDavid du Colombier 		d1->gid = cons.gid;
75201a344a2SDavid du Colombier 	} else {
75301a344a2SDavid du Colombier 		d1->uid = f->uid;
75401a344a2SDavid du Colombier 		d1->gid = d->gid;
75501a344a2SDavid du Colombier 		in->perm &= d->mode | ~0666;
75601a344a2SDavid du Colombier 		if(in->perm & PDIR)
75701a344a2SDavid du Colombier 			in->perm &= d->mode | ~0777;
75801a344a2SDavid du Colombier 	}
75901a344a2SDavid du Colombier 	d1->qid.path = path;
76001a344a2SDavid du Colombier 	d1->qid.version = 0;
76101a344a2SDavid du Colombier 	d1->mode = DALLOC | (in->perm & 0777);
76201a344a2SDavid du Colombier 	if(in->perm & PDIR) {
76301a344a2SDavid du Colombier 		d1->mode |= DDIR;
76401a344a2SDavid du Colombier 		d1->qid.path |= QPDIR;
76501a344a2SDavid du Colombier 	}
76601a344a2SDavid du Colombier 	if(in->perm & PAPND)
76701a344a2SDavid du Colombier 		d1->mode |= DAPND;
76801a344a2SDavid du Colombier 	t = 0;
76901a344a2SDavid du Colombier 	if(in->perm & PLOCK) {
77001a344a2SDavid du Colombier 		d1->mode |= DLOCK;
77101a344a2SDavid du Colombier 		t = tlocked(p1, d1);
77201a344a2SDavid du Colombier 		/* if nil, out of tlock structures */
77301a344a2SDavid du Colombier 	}
77401a344a2SDavid du Colombier 	accessdir(p1, d1, FWRITE, f->uid);
77501a344a2SDavid du Colombier 	mkqid(&qid, d1, 0);
77601a344a2SDavid du Colombier 	putbuf(p1);
77701a344a2SDavid du Colombier 	accessdir(p, d, FWRITE, f->uid);
77801a344a2SDavid du Colombier 
77901a344a2SDavid du Colombier 	/*
78001a344a2SDavid du Colombier 	 * do a walk to new directory entry
78101a344a2SDavid du Colombier 	 */
78201a344a2SDavid du Colombier 	w = newwp();
78301a344a2SDavid du Colombier 	if(!w) {
78401a344a2SDavid du Colombier 		ou->err = Ewalk;
78501a344a2SDavid du Colombier 		goto out;
78601a344a2SDavid du Colombier 	}
78701a344a2SDavid du Colombier 	w->addr = f->addr;
78801a344a2SDavid du Colombier 	w->slot = f->slot;
78901a344a2SDavid du Colombier 	w->up = f->wpath;
79001a344a2SDavid du Colombier 	f->wpath = w;
79101a344a2SDavid du Colombier 	f->qid = qid;
79201a344a2SDavid du Colombier 	f->tlock = t;
79301a344a2SDavid du Colombier 	if(t)
79401a344a2SDavid du Colombier 		t->file = f;
79501a344a2SDavid du Colombier 	f->lastra = 1;
79601a344a2SDavid du Colombier 	if(in->mode & ORCLOSE)
79701a344a2SDavid du Colombier 		fmod |= FREMOV;
79801a344a2SDavid du Colombier 	f->open = fmod;
79901a344a2SDavid du Colombier 	f->addr = addr1;
80001a344a2SDavid du Colombier 	f->slot = slot1;
80101a344a2SDavid du Colombier 	mkqid9p1(&ou->qid, &qid);
80201a344a2SDavid du Colombier 	goto out;
80301a344a2SDavid du Colombier 
80401a344a2SDavid du Colombier badaccess:
80501a344a2SDavid du Colombier 	ou->err = Eaccess;
80601a344a2SDavid du Colombier 	goto out;
80701a344a2SDavid du Colombier 
80801a344a2SDavid du Colombier phase:
80901a344a2SDavid du Colombier 	ou->err = Ephase;
81001a344a2SDavid du Colombier 
81101a344a2SDavid du Colombier out:
81201a344a2SDavid du Colombier 	if(p)
81301a344a2SDavid du Colombier 		putbuf(p);
81401a344a2SDavid du Colombier 	if(f)
81501a344a2SDavid du Colombier 		qunlock(f);
81601a344a2SDavid du Colombier 	ou->fid = in->fid;
81701a344a2SDavid du Colombier }
81801a344a2SDavid du Colombier 
81901a344a2SDavid du Colombier static void
f_read(Chan * cp,Fcall * in,Fcall * ou)82001a344a2SDavid du Colombier f_read(Chan *cp, Fcall *in, Fcall *ou)
82101a344a2SDavid du Colombier {
82201a344a2SDavid du Colombier 	Iobuf *p, *p1;
82301a344a2SDavid du Colombier 	File *f;
82401a344a2SDavid du Colombier 	Dentry *d, *d1;
82501a344a2SDavid du Colombier 	Tlock *t;
82601a344a2SDavid du Colombier 	Off addr, offset;
82701a344a2SDavid du Colombier 	Timet tim;
82801a344a2SDavid du Colombier 	int nread, count, n, o, slot;
82901a344a2SDavid du Colombier 
83001a344a2SDavid du Colombier 	if(CHAT(cp)) {
83101a344a2SDavid du Colombier 		print("c_read %d\n", cp->chan);
83201a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
83301a344a2SDavid du Colombier 		print("\toffset = %lld\n", (Wideoff)in->offset);
83401a344a2SDavid du Colombier 		print("\tcount = %ld\n", in->count);
83501a344a2SDavid du Colombier 	}
83601a344a2SDavid du Colombier 
83701a344a2SDavid du Colombier 	p = 0;
83801a344a2SDavid du Colombier 	count = in->count;
83901a344a2SDavid du Colombier 	offset = in->offset;
84001a344a2SDavid du Colombier 	nread = 0;
84101a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
84201a344a2SDavid du Colombier 	if(!f) {
84301a344a2SDavid du Colombier 		ou->err = Efid;
84401a344a2SDavid du Colombier 		goto out;
84501a344a2SDavid du Colombier 	}
84601a344a2SDavid du Colombier 	if(!(f->open & FREAD)) {
84701a344a2SDavid du Colombier 		ou->err = Eopen;
84801a344a2SDavid du Colombier 		goto out;
84901a344a2SDavid du Colombier 	}
85001a344a2SDavid du Colombier 	if(count < 0 || count > MAXDAT) {
85101a344a2SDavid du Colombier 		ou->err = Ecount;
85201a344a2SDavid du Colombier 		goto out;
85301a344a2SDavid du Colombier 	}
85401a344a2SDavid du Colombier 	if(offset < 0) {
85501a344a2SDavid du Colombier 		ou->err = Eoffset;
85601a344a2SDavid du Colombier 		goto out;
85701a344a2SDavid du Colombier 	}
85801a344a2SDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Brd);
85901a344a2SDavid du Colombier 	d = getdir(p, f->slot);
86001a344a2SDavid du Colombier 	if(!d || !(d->mode & DALLOC)) {
86101a344a2SDavid du Colombier 		ou->err = Ealloc;
86201a344a2SDavid du Colombier 		goto out;
86301a344a2SDavid du Colombier 	}
86401a344a2SDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
86501a344a2SDavid du Colombier 		goto out;
86601a344a2SDavid du Colombier 	if(t = f->tlock) {
86701a344a2SDavid du Colombier 		tim = toytime();
86801a344a2SDavid du Colombier 		if(t->time < tim || t->file != f) {
86901a344a2SDavid du Colombier 			ou->err = Ebroken;
87001a344a2SDavid du Colombier 			goto out;
87101a344a2SDavid du Colombier 		}
87201a344a2SDavid du Colombier 		/* renew the lock */
87301a344a2SDavid du Colombier 		t->time = tim + TLOCK;
87401a344a2SDavid du Colombier 	}
87501a344a2SDavid du Colombier 	accessdir(p, d, FREAD, f->uid);
87601a344a2SDavid du Colombier 	if(d->mode & DDIR) {
87701a344a2SDavid du Colombier 		addr = 0;
87801a344a2SDavid du Colombier 		goto dread;
87901a344a2SDavid du Colombier 	}
88001a344a2SDavid du Colombier 
88101a344a2SDavid du Colombier 	/* XXXX terrible hack to get at raw data XXXX */
88201a344a2SDavid du Colombier 	if(rawreadok && strncmp(d->name, "--raw--", 7) == 0) {
88301a344a2SDavid du Colombier 		Device *dev;
88401a344a2SDavid du Colombier 		Devsize boff, bsize;
88501a344a2SDavid du Colombier 
88601a344a2SDavid du Colombier 		dev = p->dev;
88701a344a2SDavid du Colombier 		putbuf(p);
88801a344a2SDavid du Colombier 		p = 0;
88901a344a2SDavid du Colombier 
89001a344a2SDavid du Colombier 		boff = number(d->name + 7, 0, 10) * 100000;
89101a344a2SDavid du Colombier 		if(boff < 0)
89201a344a2SDavid du Colombier 			boff = 0;
89301a344a2SDavid du Colombier 		if(boff > devsize(dev))
89401a344a2SDavid du Colombier 			boff = devsize(dev);
89501a344a2SDavid du Colombier 		bsize = devsize(dev) - boff;
89601a344a2SDavid du Colombier 
89701a344a2SDavid du Colombier 		if(offset+count >= 100000*RBUFSIZE)
89801a344a2SDavid du Colombier 			count = 100000*RBUFSIZE - offset;
89901a344a2SDavid du Colombier 
90001a344a2SDavid du Colombier 		if((offset+count)/RBUFSIZE >= bsize)
90101a344a2SDavid du Colombier 			/* will not overflow */
90201a344a2SDavid du Colombier 			count = bsize*RBUFSIZE - offset;
90301a344a2SDavid du Colombier 
90401a344a2SDavid du Colombier 		while(count > 0) {
90501a344a2SDavid du Colombier 			addr = offset / RBUFSIZE;
90601a344a2SDavid du Colombier 			addr += boff;
90701a344a2SDavid du Colombier 			o = offset % RBUFSIZE;
90801a344a2SDavid du Colombier 			n = RBUFSIZE - o;
90901a344a2SDavid du Colombier 			if(n > count)
91001a344a2SDavid du Colombier 				n = count;
91101a344a2SDavid du Colombier 
91201a344a2SDavid du Colombier 			p1 = getbuf(dev, addr, Brd);
91301a344a2SDavid du Colombier 			if(p1) {
91401a344a2SDavid du Colombier 				memmove(ou->data+nread, p1->iobuf+o, n);
91501a344a2SDavid du Colombier 				putbuf(p1);
91601a344a2SDavid du Colombier 			} else
91701a344a2SDavid du Colombier 				memset(ou->data+nread, 0, n);
91801a344a2SDavid du Colombier 			count -= n;
91901a344a2SDavid du Colombier 			nread += n;
92001a344a2SDavid du Colombier 			offset += n;
92101a344a2SDavid du Colombier 		}
92201a344a2SDavid du Colombier 		goto out;
92301a344a2SDavid du Colombier 	}
92401a344a2SDavid du Colombier 
92501a344a2SDavid du Colombier 	if(offset+count > d->size)
92601a344a2SDavid du Colombier 		count = d->size - offset;
92701a344a2SDavid du Colombier 	while(count > 0) {
92801a344a2SDavid du Colombier 		if(p == 0) {
92901a344a2SDavid du Colombier 			p = getbuf(f->fs->dev, f->addr, Brd);
93001a344a2SDavid du Colombier 			d = getdir(p, f->slot);
93101a344a2SDavid du Colombier 			if(!d || !(d->mode & DALLOC)) {
93201a344a2SDavid du Colombier 				ou->err = Ealloc;
93301a344a2SDavid du Colombier 				goto out;
93401a344a2SDavid du Colombier 			}
93501a344a2SDavid du Colombier 		}
93601a344a2SDavid du Colombier 		addr = offset / BUFSIZE;
93701a344a2SDavid du Colombier 		f->lastra = dbufread(p, d, addr, f->lastra, f->uid);
93801a344a2SDavid du Colombier 		o = offset % BUFSIZE;
93901a344a2SDavid du Colombier 		n = BUFSIZE - o;
94001a344a2SDavid du Colombier 		if(n > count)
94101a344a2SDavid du Colombier 			n = count;
94201a344a2SDavid du Colombier 		p1 = dnodebuf1(p, d, addr, 0, f->uid);
94301a344a2SDavid du Colombier 		p = 0;
94401a344a2SDavid du Colombier 		if(p1) {
94501a344a2SDavid du Colombier 			if(checktag(p1, Tfile, QPNONE)) {
94601a344a2SDavid du Colombier 				ou->err = Ephase;
94701a344a2SDavid du Colombier 				putbuf(p1);
94801a344a2SDavid du Colombier 				goto out;
94901a344a2SDavid du Colombier 			}
95001a344a2SDavid du Colombier 			memmove(ou->data+nread, p1->iobuf+o, n);
95101a344a2SDavid du Colombier 			putbuf(p1);
95201a344a2SDavid du Colombier 		} else
95301a344a2SDavid du Colombier 			memset(ou->data+nread, 0, n);
95401a344a2SDavid du Colombier 		count -= n;
95501a344a2SDavid du Colombier 		nread += n;
95601a344a2SDavid du Colombier 		offset += n;
95701a344a2SDavid du Colombier 	}
95801a344a2SDavid du Colombier 	goto out;
95901a344a2SDavid du Colombier 
96001a344a2SDavid du Colombier dread:
96101a344a2SDavid du Colombier 	for (;;) {
96201a344a2SDavid du Colombier 		if(p == 0) {
96301a344a2SDavid du Colombier 			p = getbuf(f->fs->dev, f->addr, Brd);
96401a344a2SDavid du Colombier 			d = getdir(p, f->slot);
96501a344a2SDavid du Colombier 			if(!d || !(d->mode & DALLOC)) {
96601a344a2SDavid du Colombier 				ou->err = Ealloc;
96701a344a2SDavid du Colombier 				goto out;
96801a344a2SDavid du Colombier 			}
96901a344a2SDavid du Colombier 		}
97001a344a2SDavid du Colombier 		p1 = dnodebuf1(p, d, addr, 0, f->uid);
97101a344a2SDavid du Colombier 		p = 0;
97201a344a2SDavid du Colombier 		if(!p1)
97301a344a2SDavid du Colombier 			goto out;
97401a344a2SDavid du Colombier 		if(checktag(p1, Tdir, QPNONE)) {
97501a344a2SDavid du Colombier 			ou->err = Ephase;
97601a344a2SDavid du Colombier 			putbuf(p1);
97701a344a2SDavid du Colombier 			goto out;
97801a344a2SDavid du Colombier 		}
97901a344a2SDavid du Colombier 		n = DIRREC;
98001a344a2SDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
98101a344a2SDavid du Colombier 			d1 = getdir(p1, slot);
98201a344a2SDavid du Colombier 			if(!(d1->mode & DALLOC))
98301a344a2SDavid du Colombier 				continue;
98401a344a2SDavid du Colombier 			if(offset >= n) {
98501a344a2SDavid du Colombier 				offset -= n;
98601a344a2SDavid du Colombier 				continue;
98701a344a2SDavid du Colombier 			}
98801a344a2SDavid du Colombier 			if(count < n) {
98901a344a2SDavid du Colombier 				putbuf(p1);
99001a344a2SDavid du Colombier 				goto out;
99101a344a2SDavid du Colombier 			}
99201a344a2SDavid du Colombier 			if(convD2M9p1(d1, ou->data+nread) != n)
99301a344a2SDavid du Colombier 				print("9p1: dirread convD2M1990\n");
99401a344a2SDavid du Colombier 			nread += n;
99501a344a2SDavid du Colombier 			count -= n;
99601a344a2SDavid du Colombier 		}
99701a344a2SDavid du Colombier 		putbuf(p1);
99801a344a2SDavid du Colombier 		addr++;
99901a344a2SDavid du Colombier 	}
100001a344a2SDavid du Colombier out:
100101a344a2SDavid du Colombier 	count = in->count - nread;
100201a344a2SDavid du Colombier 	if(count > 0)
100301a344a2SDavid du Colombier 		memset(ou->data+nread, 0, count);
100401a344a2SDavid du Colombier 	if(p)
100501a344a2SDavid du Colombier 		putbuf(p);
100601a344a2SDavid du Colombier 	if(f)
100701a344a2SDavid du Colombier 		qunlock(f);
100801a344a2SDavid du Colombier 	ou->fid = in->fid;
100901a344a2SDavid du Colombier 	ou->count = nread;
101001a344a2SDavid du Colombier 	if(CHAT(cp))
101101a344a2SDavid du Colombier 		print("\tnread = %d\n", nread);
101201a344a2SDavid du Colombier }
101301a344a2SDavid du Colombier 
101401a344a2SDavid du Colombier static void
f_write(Chan * cp,Fcall * in,Fcall * ou)101501a344a2SDavid du Colombier f_write(Chan *cp, Fcall *in, Fcall *ou)
101601a344a2SDavid du Colombier {
101701a344a2SDavid du Colombier 	Iobuf *p, *p1;
101801a344a2SDavid du Colombier 	Dentry *d;
101901a344a2SDavid du Colombier 	File *f;
102001a344a2SDavid du Colombier 	Tlock *t;
102101a344a2SDavid du Colombier 	Off offset, addr, qpath;
102201a344a2SDavid du Colombier 	Timet tim;
102301a344a2SDavid du Colombier 	int count, nwrite, o, n;
102401a344a2SDavid du Colombier 
102501a344a2SDavid du Colombier 	if(CHAT(cp)) {
102601a344a2SDavid du Colombier 		print("c_write %d\n", cp->chan);
102701a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
102801a344a2SDavid du Colombier 		print("\toffset = %lld\n", (Wideoff)in->offset);
102901a344a2SDavid du Colombier 		print("\tcount = %ld\n", in->count);
103001a344a2SDavid du Colombier 	}
103101a344a2SDavid du Colombier 
103201a344a2SDavid du Colombier 	offset = in->offset;
103301a344a2SDavid du Colombier 	count = in->count;
103401a344a2SDavid du Colombier 	nwrite = 0;
103501a344a2SDavid du Colombier 	p = 0;
103601a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
103701a344a2SDavid du Colombier 	if(!f) {
103801a344a2SDavid du Colombier 		ou->err = Efid;
103901a344a2SDavid du Colombier 		goto out;
104001a344a2SDavid du Colombier 	}
104101a344a2SDavid du Colombier 	if(!(f->open & FWRITE)) {
104201a344a2SDavid du Colombier 		ou->err = Eopen;
104301a344a2SDavid du Colombier 		goto out;
104401a344a2SDavid du Colombier 	}
104501a344a2SDavid du Colombier 	if(f->fs->dev->type == Devro) {
104601a344a2SDavid du Colombier 		ou->err = Eronly;
104701a344a2SDavid du Colombier 		goto out;
104801a344a2SDavid du Colombier 	}
104901a344a2SDavid du Colombier 	if(count < 0 || count > MAXDAT) {
105001a344a2SDavid du Colombier 		ou->err = Ecount;
105101a344a2SDavid du Colombier 		goto out;
105201a344a2SDavid du Colombier 	}
105301a344a2SDavid du Colombier 	if(offset < 0) {
105401a344a2SDavid du Colombier 		ou->err = Eoffset;
105501a344a2SDavid du Colombier 		goto out;
105601a344a2SDavid du Colombier 	}
105701a344a2SDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Brd|Bmod);
105801a344a2SDavid du Colombier 	d = getdir(p, f->slot);
105901a344a2SDavid du Colombier 	if(!d || !(d->mode & DALLOC)) {
106001a344a2SDavid du Colombier 		ou->err = Ealloc;
106101a344a2SDavid du Colombier 		goto out;
106201a344a2SDavid du Colombier 	}
106301a344a2SDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
106401a344a2SDavid du Colombier 		goto out;
106501a344a2SDavid du Colombier 	if(t = f->tlock) {
106601a344a2SDavid du Colombier 		tim = toytime();
106701a344a2SDavid du Colombier 		if(t->time < tim || t->file != f) {
106801a344a2SDavid du Colombier 			ou->err = Ebroken;
106901a344a2SDavid du Colombier 			goto out;
107001a344a2SDavid du Colombier 		}
107101a344a2SDavid du Colombier 		/* renew the lock */
107201a344a2SDavid du Colombier 		t->time = tim + TLOCK;
107301a344a2SDavid du Colombier 	}
107401a344a2SDavid du Colombier 	accessdir(p, d, FWRITE, f->uid);
107501a344a2SDavid du Colombier 	if(d->mode & DAPND)
107601a344a2SDavid du Colombier 		offset = d->size;
107701a344a2SDavid du Colombier 	if(offset+count > d->size)
107801a344a2SDavid du Colombier 		d->size = offset+count;
107901a344a2SDavid du Colombier 	while(count > 0) {
108001a344a2SDavid du Colombier 		if(p == 0) {
108101a344a2SDavid du Colombier 			p = getbuf(f->fs->dev, f->addr, Brd|Bmod);
108201a344a2SDavid du Colombier 			d = getdir(p, f->slot);
108301a344a2SDavid du Colombier 			if(!d || !(d->mode & DALLOC)) {
108401a344a2SDavid du Colombier 				ou->err = Ealloc;
108501a344a2SDavid du Colombier 				goto out;
108601a344a2SDavid du Colombier 			}
108701a344a2SDavid du Colombier 		}
108801a344a2SDavid du Colombier 		addr = offset / BUFSIZE;
108901a344a2SDavid du Colombier 		o = offset % BUFSIZE;
109001a344a2SDavid du Colombier 		n = BUFSIZE - o;
109101a344a2SDavid du Colombier 		if(n > count)
109201a344a2SDavid du Colombier 			n = count;
109301a344a2SDavid du Colombier 		qpath = d->qid.path;
109401a344a2SDavid du Colombier 		p1 = dnodebuf1(p, d, addr, Tfile, f->uid);
109501a344a2SDavid du Colombier 		p = 0;
109601a344a2SDavid du Colombier 		if(p1 == 0) {
109701a344a2SDavid du Colombier 			ou->err = Efull;
109801a344a2SDavid du Colombier 			goto out;
109901a344a2SDavid du Colombier 		}
110001a344a2SDavid du Colombier 		if(checktag(p1, Tfile, qpath)) {
110101a344a2SDavid du Colombier 			putbuf(p1);
110201a344a2SDavid du Colombier 			ou->err = Ephase;
110301a344a2SDavid du Colombier 			goto out;
110401a344a2SDavid du Colombier 		}
110501a344a2SDavid du Colombier 		memmove(p1->iobuf+o, in->data+nwrite, n);
110601a344a2SDavid du Colombier 		p1->flags |= Bmod;
110701a344a2SDavid du Colombier 		putbuf(p1);
110801a344a2SDavid du Colombier 		count -= n;
110901a344a2SDavid du Colombier 		nwrite += n;
111001a344a2SDavid du Colombier 		offset += n;
111101a344a2SDavid du Colombier 	}
111201a344a2SDavid du Colombier 	if(CHAT(cp))
111301a344a2SDavid du Colombier 		print("\tnwrite = %d\n", nwrite);
111401a344a2SDavid du Colombier 
111501a344a2SDavid du Colombier out:
111601a344a2SDavid du Colombier 	if(p)
111701a344a2SDavid du Colombier 		putbuf(p);
111801a344a2SDavid du Colombier 	if(f)
111901a344a2SDavid du Colombier 		qunlock(f);
112001a344a2SDavid du Colombier 	ou->fid = in->fid;
112101a344a2SDavid du Colombier 	ou->count = nwrite;
112201a344a2SDavid du Colombier }
112301a344a2SDavid du Colombier 
112401a344a2SDavid du Colombier int
doremove(File * f,int wok)112501a344a2SDavid du Colombier doremove(File *f, int wok)
112601a344a2SDavid du Colombier {
112701a344a2SDavid du Colombier 	Iobuf *p, *p1;
112801a344a2SDavid du Colombier 	Dentry *d, *d1;
112901a344a2SDavid du Colombier 	Off addr;
113001a344a2SDavid du Colombier 	int slot, err;
113101a344a2SDavid du Colombier 
113201a344a2SDavid du Colombier 	p = 0;
113301a344a2SDavid du Colombier 	p1 = 0;
113401a344a2SDavid du Colombier 	if(f->fs->dev->type == Devro) {
113501a344a2SDavid du Colombier 		err = Eronly;
113601a344a2SDavid du Colombier 		goto out;
113701a344a2SDavid du Colombier 	}
113801a344a2SDavid du Colombier 	/*
113901a344a2SDavid du Colombier 	 * check on parent directory of file to be deleted
114001a344a2SDavid du Colombier 	 */
114101a344a2SDavid du Colombier 	if(f->wpath == 0 || f->wpath->addr == f->addr) {
114201a344a2SDavid du Colombier 		err = Ephase;
114301a344a2SDavid du Colombier 		goto out;
114401a344a2SDavid du Colombier 	}
114501a344a2SDavid du Colombier 	p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
114601a344a2SDavid du Colombier 	d1 = getdir(p1, f->wpath->slot);
114701a344a2SDavid du Colombier 	if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
114801a344a2SDavid du Colombier 		err = Ephase;
114901a344a2SDavid du Colombier 		goto out;
115001a344a2SDavid du Colombier 	}
115101a344a2SDavid du Colombier 	if(iaccess(f, d1, DWRITE) && !wok) {
115201a344a2SDavid du Colombier 		err = Eaccess;
115301a344a2SDavid du Colombier 		goto out;
115401a344a2SDavid du Colombier 	}
115501a344a2SDavid du Colombier 	accessdir(p1, d1, FWRITE, f->uid);
115601a344a2SDavid du Colombier 	putbuf(p1);
115701a344a2SDavid du Colombier 	p1 = 0;
115801a344a2SDavid du Colombier 
115901a344a2SDavid du Colombier 	/*
116001a344a2SDavid du Colombier 	 * check on file to be deleted
116101a344a2SDavid du Colombier 	 */
116201a344a2SDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Brd);
116301a344a2SDavid du Colombier 	d = getdir(p, f->slot);
116401a344a2SDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
116501a344a2SDavid du Colombier 		err = Ealloc;
116601a344a2SDavid du Colombier 		goto out;
116701a344a2SDavid du Colombier 	}
116801a344a2SDavid du Colombier 	if(err = mkqidcmp(&f->qid, d))
116901a344a2SDavid du Colombier 		goto out;
117001a344a2SDavid du Colombier 
117101a344a2SDavid du Colombier 	/*
117201a344a2SDavid du Colombier 	 * if deleting a directory, make sure it is empty
117301a344a2SDavid du Colombier 	 */
117401a344a2SDavid du Colombier 	if((d->mode & DDIR))
117501a344a2SDavid du Colombier 	for(addr=0;; addr++) {
117601a344a2SDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0, f->uid);
117701a344a2SDavid du Colombier 		if(!p1)
117801a344a2SDavid du Colombier 			break;
117901a344a2SDavid du Colombier 		if(checktag(p1, Tdir, d->qid.path)) {
118001a344a2SDavid du Colombier 			err = Ephase;
118101a344a2SDavid du Colombier 			goto out;
118201a344a2SDavid du Colombier 		}
118301a344a2SDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
118401a344a2SDavid du Colombier 			d1 = getdir(p1, slot);
118501a344a2SDavid du Colombier 			if(!(d1->mode & DALLOC))
118601a344a2SDavid du Colombier 				continue;
118701a344a2SDavid du Colombier 			err = Eempty;
118801a344a2SDavid du Colombier 			goto out;
118901a344a2SDavid du Colombier 		}
119001a344a2SDavid du Colombier 		putbuf(p1);
119101a344a2SDavid du Colombier 	}
119201a344a2SDavid du Colombier 
119301a344a2SDavid du Colombier 	/*
119401a344a2SDavid du Colombier 	 * do it
119501a344a2SDavid du Colombier 	 */
119601a344a2SDavid du Colombier 	dtrunc(p, d, f->uid);
119701a344a2SDavid du Colombier 	memset(d, 0, sizeof(Dentry));
119801a344a2SDavid du Colombier 	settag(p, Tdir, QPNONE);
119901a344a2SDavid du Colombier 
120001a344a2SDavid du Colombier out:
120101a344a2SDavid du Colombier 	if(p1)
120201a344a2SDavid du Colombier 		putbuf(p1);
120301a344a2SDavid du Colombier 	if(p)
120401a344a2SDavid du Colombier 		putbuf(p);
120501a344a2SDavid du Colombier 	return err;
120601a344a2SDavid du Colombier }
120701a344a2SDavid du Colombier 
120801a344a2SDavid du Colombier static int
doclunk(File * f,int remove,int wok)120901a344a2SDavid du Colombier doclunk(File* f, int remove, int wok)
121001a344a2SDavid du Colombier {
121101a344a2SDavid du Colombier 	Tlock *t;
121201a344a2SDavid du Colombier 	int err;
121301a344a2SDavid du Colombier 
121401a344a2SDavid du Colombier 	err = 0;
121501a344a2SDavid du Colombier 	if(t = f->tlock) {
121601a344a2SDavid du Colombier 		if(t->file == f)
121701a344a2SDavid du Colombier 			t->time = 0;	/* free the lock */
121801a344a2SDavid du Colombier 		f->tlock = 0;
121901a344a2SDavid du Colombier 	}
122001a344a2SDavid du Colombier 	if(remove)
122101a344a2SDavid du Colombier 		err = doremove(f, wok);
122201a344a2SDavid du Colombier 	f->open = 0;
122301a344a2SDavid du Colombier 	freewp(f->wpath);
122401a344a2SDavid du Colombier 	freefp(f);
122501a344a2SDavid du Colombier 
122601a344a2SDavid du Colombier 	return err;
122701a344a2SDavid du Colombier }
122801a344a2SDavid du Colombier 
122901a344a2SDavid du Colombier static void
f_clunk(Chan * cp,Fcall * in,Fcall * ou)123001a344a2SDavid du Colombier f_clunk(Chan *cp, Fcall *in, Fcall *ou)
123101a344a2SDavid du Colombier {
123201a344a2SDavid du Colombier 	File *f;
123301a344a2SDavid du Colombier 
123401a344a2SDavid du Colombier 	if(CHAT(cp)) {
123501a344a2SDavid du Colombier 		print("c_clunk %d\n", cp->chan);
123601a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
123701a344a2SDavid du Colombier 	}
123801a344a2SDavid du Colombier 
123901a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
124001a344a2SDavid du Colombier 	if(!f)
124101a344a2SDavid du Colombier 		ou->err = Efid;
124201a344a2SDavid du Colombier 	else {
124301a344a2SDavid du Colombier 		doclunk(f, f->open & FREMOV, 0);
124401a344a2SDavid du Colombier 		qunlock(f);
124501a344a2SDavid du Colombier 	}
124601a344a2SDavid du Colombier 	ou->fid = in->fid;
124701a344a2SDavid du Colombier }
124801a344a2SDavid du Colombier 
124901a344a2SDavid du Colombier static void
f_remove(Chan * cp,Fcall * in,Fcall * ou)125001a344a2SDavid du Colombier f_remove(Chan *cp, Fcall *in, Fcall *ou)
125101a344a2SDavid du Colombier {
125201a344a2SDavid du Colombier 	File *f;
125301a344a2SDavid du Colombier 
125401a344a2SDavid du Colombier 	if(CHAT(cp)) {
125501a344a2SDavid du Colombier 		print("c_remove %d\n", cp->chan);
125601a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
125701a344a2SDavid du Colombier 	}
125801a344a2SDavid du Colombier 
125901a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
126001a344a2SDavid du Colombier 	if(!f)
126101a344a2SDavid du Colombier 		ou->err = Efid;
126201a344a2SDavid du Colombier 	else {
126301a344a2SDavid du Colombier 		ou->err = doclunk(f, 1, cp==cons.chan);
126401a344a2SDavid du Colombier 		qunlock(f);
126501a344a2SDavid du Colombier 	}
126601a344a2SDavid du Colombier 	ou->fid = in->fid;
126701a344a2SDavid du Colombier }
126801a344a2SDavid du Colombier 
126901a344a2SDavid du Colombier static void
f_stat(Chan * cp,Fcall * in,Fcall * ou)127001a344a2SDavid du Colombier f_stat(Chan *cp, Fcall *in, Fcall *ou)
127101a344a2SDavid du Colombier {
127201a344a2SDavid du Colombier 	Iobuf *p;
127301a344a2SDavid du Colombier 	Dentry *d;
127401a344a2SDavid du Colombier 	File *f;
127501a344a2SDavid du Colombier 
127601a344a2SDavid du Colombier 	if(CHAT(cp)) {
127701a344a2SDavid du Colombier 		print("c_stat %d\n", cp->chan);
127801a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
127901a344a2SDavid du Colombier 	}
128001a344a2SDavid du Colombier 
128101a344a2SDavid du Colombier 	p = 0;
128201a344a2SDavid du Colombier 	memset(ou->stat, 0, sizeof(ou->stat));
128301a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
128401a344a2SDavid du Colombier 	if(!f) {
128501a344a2SDavid du Colombier 		ou->err = Efid;
128601a344a2SDavid du Colombier 		goto out;
128701a344a2SDavid du Colombier 	}
128801a344a2SDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Brd);
128901a344a2SDavid du Colombier 	d = getdir(p, f->slot);
129001a344a2SDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
129101a344a2SDavid du Colombier 		ou->err = Ealloc;
129201a344a2SDavid du Colombier 		goto out;
129301a344a2SDavid du Colombier 	}
129401a344a2SDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
129501a344a2SDavid du Colombier 		goto out;
129601a344a2SDavid du Colombier 	if(d->qid.path == QPROOT)	/* stat of root gives time */
129701a344a2SDavid du Colombier 		d->atime = time(nil);
129801a344a2SDavid du Colombier 	if(convD2M9p1(d, ou->stat) != DIRREC)
129901a344a2SDavid du Colombier 		print("9p1: stat convD2M\n");
130001a344a2SDavid du Colombier 
130101a344a2SDavid du Colombier out:
130201a344a2SDavid du Colombier 	if(p)
130301a344a2SDavid du Colombier 		putbuf(p);
130401a344a2SDavid du Colombier 	if(f)
130501a344a2SDavid du Colombier 		qunlock(f);
130601a344a2SDavid du Colombier 	ou->fid = in->fid;
130701a344a2SDavid du Colombier }
130801a344a2SDavid du Colombier 
130901a344a2SDavid du Colombier static void
f_wstat(Chan * cp,Fcall * in,Fcall * ou)131001a344a2SDavid du Colombier f_wstat(Chan *cp, Fcall *in, Fcall *ou)
131101a344a2SDavid du Colombier {
131201a344a2SDavid du Colombier 	Iobuf *p, *p1;
131301a344a2SDavid du Colombier 	Dentry *d, *d1, xd;
131401a344a2SDavid du Colombier 	File *f;
131501a344a2SDavid du Colombier 	int slot;
131601a344a2SDavid du Colombier 	Off addr;
131701a344a2SDavid du Colombier 
131801a344a2SDavid du Colombier 	if(CHAT(cp)) {
131901a344a2SDavid du Colombier 		print("c_wstat %d\n", cp->chan);
132001a344a2SDavid du Colombier 		print("\tfid = %d\n", in->fid);
132101a344a2SDavid du Colombier 	}
132201a344a2SDavid du Colombier 
132301a344a2SDavid du Colombier 	p = 0;
132401a344a2SDavid du Colombier 	p1 = 0;
132501a344a2SDavid du Colombier 	d1 = 0;
132601a344a2SDavid du Colombier 	f = filep(cp, in->fid, 0);
132701a344a2SDavid du Colombier 	if(!f) {
132801a344a2SDavid du Colombier 		ou->err = Efid;
132901a344a2SDavid du Colombier 		goto out;
133001a344a2SDavid du Colombier 	}
133101a344a2SDavid du Colombier 	if(f->fs->dev->type == Devro) {
133201a344a2SDavid du Colombier 		ou->err = Eronly;
133301a344a2SDavid du Colombier 		goto out;
133401a344a2SDavid du Colombier 	}
133501a344a2SDavid du Colombier 
133601a344a2SDavid du Colombier 	/*
133701a344a2SDavid du Colombier 	 * first get parent
133801a344a2SDavid du Colombier 	 */
133901a344a2SDavid du Colombier 	if(f->wpath) {
134001a344a2SDavid du Colombier 		p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
134101a344a2SDavid du Colombier 		d1 = getdir(p1, f->wpath->slot);
134201a344a2SDavid du Colombier 		if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
134301a344a2SDavid du Colombier 			ou->err = Ephase;
134401a344a2SDavid du Colombier 			goto out;
134501a344a2SDavid du Colombier 		}
134601a344a2SDavid du Colombier 	}
134701a344a2SDavid du Colombier 
134801a344a2SDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Brd);
134901a344a2SDavid du Colombier 	d = getdir(p, f->slot);
135001a344a2SDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
135101a344a2SDavid du Colombier 		ou->err = Ealloc;
135201a344a2SDavid du Colombier 		goto out;
135301a344a2SDavid du Colombier 	}
135401a344a2SDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
135501a344a2SDavid du Colombier 		goto out;
135601a344a2SDavid du Colombier 
135701a344a2SDavid du Colombier 	convM2D9p1(in->stat, &xd);
135801a344a2SDavid du Colombier 	if(CHAT(cp)) {
135901a344a2SDavid du Colombier 		print("\td.name = %s\n", xd.name);
136001a344a2SDavid du Colombier 		print("\td.uid  = %d\n", xd.uid);
136101a344a2SDavid du Colombier 		print("\td.gid  = %d\n", xd.gid);
136201a344a2SDavid du Colombier 		print("\td.mode = %o\n", xd.mode);
136301a344a2SDavid du Colombier 	}
136401a344a2SDavid du Colombier 
136501a344a2SDavid du Colombier 	/*
136601a344a2SDavid du Colombier 	 * if user none,
136701a344a2SDavid du Colombier 	 * cant do anything
136801a344a2SDavid du Colombier 	 */
136901a344a2SDavid du Colombier 	if(f->uid == 0) {
137001a344a2SDavid du Colombier 		ou->err = Eaccess;
137101a344a2SDavid du Colombier 		goto out;
137201a344a2SDavid du Colombier 	}
137301a344a2SDavid du Colombier 
137401a344a2SDavid du Colombier 	/*
137501a344a2SDavid du Colombier 	 * if chown,
137601a344a2SDavid du Colombier 	 * must be god
137701a344a2SDavid du Colombier 	 */
137801a344a2SDavid du Colombier 	if(xd.uid != d->uid && !wstatallow) { /* set to allow chown during boot */
137901a344a2SDavid du Colombier 		ou->err = Ewstatu;
138001a344a2SDavid du Colombier 		goto out;
138101a344a2SDavid du Colombier 	}
138201a344a2SDavid du Colombier 
138301a344a2SDavid du Colombier 	/*
138401a344a2SDavid du Colombier 	 * if chgroup,
138501a344a2SDavid du Colombier 	 * must be either
138601a344a2SDavid du Colombier 	 *	a) owner and in new group
138701a344a2SDavid du Colombier 	 *	b) leader of both groups
138801a344a2SDavid du Colombier 	 */
138901a344a2SDavid du Colombier 	if (xd.gid != d->gid &&
139001a344a2SDavid du Colombier 	    (!wstatallow && !writeallow &&  /* set to allow chgrp during boot */
139101a344a2SDavid du Colombier 	     (d->uid != f->uid || !ingroup(f->uid, xd.gid)) &&
139201a344a2SDavid du Colombier 	     (!leadgroup(f->uid, xd.gid) || !leadgroup(f->uid, d->gid)))) {
139301a344a2SDavid du Colombier 		ou->err = Ewstatg;
139401a344a2SDavid du Colombier 		goto out;
139501a344a2SDavid du Colombier 	}
139601a344a2SDavid du Colombier 
139701a344a2SDavid du Colombier 	/*
139801a344a2SDavid du Colombier 	 * if rename,
139901a344a2SDavid du Colombier 	 * must have write permission in parent
140001a344a2SDavid du Colombier 	 */
140101a344a2SDavid du Colombier 	if (strncmp(d->name, xd.name, sizeof(d->name)) != 0) {
140201a344a2SDavid du Colombier 		if (checkname(xd.name) || !d1 ||
140301a344a2SDavid du Colombier 		    strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
140401a344a2SDavid du Colombier 			ou->err = Ename;
140501a344a2SDavid du Colombier 			goto out;
140601a344a2SDavid du Colombier 		}
140701a344a2SDavid du Colombier 
140801a344a2SDavid du Colombier 		/*
140901a344a2SDavid du Colombier 		 * drop entry to prevent lock, then
141001a344a2SDavid du Colombier 		 * check that destination name is unique,
141101a344a2SDavid du Colombier 		 */
141201a344a2SDavid du Colombier 		putbuf(p);
141301a344a2SDavid du Colombier 		for(addr=0;; addr++) {
141401a344a2SDavid du Colombier 			p = dnodebuf(p1, d1, addr, 0, f->uid);
141501a344a2SDavid du Colombier 			if(!p)
141601a344a2SDavid du Colombier 				break;
141701a344a2SDavid du Colombier 			if(checktag(p, Tdir, d1->qid.path)) {
141801a344a2SDavid du Colombier 				putbuf(p);
141901a344a2SDavid du Colombier 				continue;
142001a344a2SDavid du Colombier 			}
142101a344a2SDavid du Colombier 			for(slot=0; slot<DIRPERBUF; slot++) {
142201a344a2SDavid du Colombier 				d = getdir(p, slot);
142301a344a2SDavid du Colombier 				if(!(d->mode & DALLOC))
142401a344a2SDavid du Colombier 					continue;
142501a344a2SDavid du Colombier 				if(!strncmp(xd.name, d->name, sizeof(xd.name))) {
142601a344a2SDavid du Colombier 					ou->err = Eexist;
142701a344a2SDavid du Colombier 					goto out;
142801a344a2SDavid du Colombier 				}
142901a344a2SDavid du Colombier 			}
143001a344a2SDavid du Colombier 			putbuf(p);
143101a344a2SDavid du Colombier 		}
143201a344a2SDavid du Colombier 
143301a344a2SDavid du Colombier 		/*
143401a344a2SDavid du Colombier 		 * reacquire entry
143501a344a2SDavid du Colombier 		 */
143601a344a2SDavid du Colombier 		p = getbuf(f->fs->dev, f->addr, Brd);
143701a344a2SDavid du Colombier 		d = getdir(p, f->slot);
143801a344a2SDavid du Colombier 		if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
143901a344a2SDavid du Colombier 			ou->err = Ephase;
144001a344a2SDavid du Colombier 			goto out;
144101a344a2SDavid du Colombier 		}
144201a344a2SDavid du Colombier 
144301a344a2SDavid du Colombier 		if (!wstatallow && !writeallow && /* set to allow rename during boot */
144401a344a2SDavid du Colombier 		    (!d1 || iaccess(f, d1, DWRITE))) {
144501a344a2SDavid du Colombier 			ou->err = Eaccess;
144601a344a2SDavid du Colombier 			goto out;
144701a344a2SDavid du Colombier 		}
144801a344a2SDavid du Colombier 	}
144901a344a2SDavid du Colombier 
145001a344a2SDavid du Colombier 	/*
145101a344a2SDavid du Colombier 	 * if mode/time, either
145201a344a2SDavid du Colombier 	 *	a) owner
145301a344a2SDavid du Colombier 	 *	b) leader of either group
145401a344a2SDavid du Colombier 	 */
145501a344a2SDavid du Colombier 	if (d->mtime != xd.mtime ||
145601a344a2SDavid du Colombier 	    ((d->mode^xd.mode) & (DAPND|DLOCK|0777)))
145701a344a2SDavid du Colombier 		if (!wstatallow &&	/* set to allow chmod during boot */
145801a344a2SDavid du Colombier 		    d->uid != f->uid &&
145901a344a2SDavid du Colombier 		    !leadgroup(f->uid, xd.gid) &&
146001a344a2SDavid du Colombier 		    !leadgroup(f->uid, d->gid)) {
146101a344a2SDavid du Colombier 			ou->err = Ewstatu;
146201a344a2SDavid du Colombier 			goto out;
146301a344a2SDavid du Colombier 		}
146401a344a2SDavid du Colombier 	d->mtime = xd.mtime;
146501a344a2SDavid du Colombier 	d->uid = xd.uid;
146601a344a2SDavid du Colombier 	d->gid = xd.gid;
146701a344a2SDavid du Colombier 	d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
146801a344a2SDavid du Colombier 
146901a344a2SDavid du Colombier 	strncpy(d->name, xd.name, sizeof(d->name));
147001a344a2SDavid du Colombier 	accessdir(p, d, FREAD, f->uid);
147101a344a2SDavid du Colombier 
147201a344a2SDavid du Colombier out:
147301a344a2SDavid du Colombier 	if(p)
147401a344a2SDavid du Colombier 		putbuf(p);
147501a344a2SDavid du Colombier 	if(p1)
147601a344a2SDavid du Colombier 		putbuf(p1);
147701a344a2SDavid du Colombier 	if(f)
147801a344a2SDavid du Colombier 		qunlock(f);
147901a344a2SDavid du Colombier 	ou->fid = in->fid;
148001a344a2SDavid du Colombier }
148101a344a2SDavid du Colombier 
148201a344a2SDavid du Colombier static void
f_clwalk(Chan * cp,Fcall * in,Fcall * ou)148301a344a2SDavid du Colombier f_clwalk(Chan *cp, Fcall *in, Fcall *ou)
148401a344a2SDavid du Colombier {
148501a344a2SDavid du Colombier 	int er, fid;
148601a344a2SDavid du Colombier 
148701a344a2SDavid du Colombier 	if(CHAT(cp))
148801a344a2SDavid du Colombier 		print("c_clwalk macro\n");
148901a344a2SDavid du Colombier 
149001a344a2SDavid du Colombier 	f_clone(cp, in, ou);		/* sets tag, fid */
149101a344a2SDavid du Colombier 	if(ou->err)
149201a344a2SDavid du Colombier 		return;
149301a344a2SDavid du Colombier 	fid = in->fid;
149401a344a2SDavid du Colombier 	in->fid = in->newfid;
149501a344a2SDavid du Colombier 	f_walk(cp, in, ou);		/* sets tag, fid, qid */
149601a344a2SDavid du Colombier 	er = ou->err;
149701a344a2SDavid du Colombier 	if(er == Eentry) {
149801a344a2SDavid du Colombier 		/*
149901a344a2SDavid du Colombier 		 * if error is "no entry"
150001a344a2SDavid du Colombier 		 * return non error and fid
150101a344a2SDavid du Colombier 		 */
150201a344a2SDavid du Colombier 		ou->err = 0;
150301a344a2SDavid du Colombier 		f_clunk(cp, in, ou);	/* sets tag, fid */
150401a344a2SDavid du Colombier 		ou->err = 0;
150501a344a2SDavid du Colombier 		ou->fid = fid;
150601a344a2SDavid du Colombier 		if(CHAT(cp))
150701a344a2SDavid du Colombier 			print("\terror: %s\n", errstr9p[er]);
150801a344a2SDavid du Colombier 	} else if(er) {
150901a344a2SDavid du Colombier 		/*
151001a344a2SDavid du Colombier 		 * if any other error
151101a344a2SDavid du Colombier 		 * return an error
151201a344a2SDavid du Colombier 		 */
151301a344a2SDavid du Colombier 		ou->err = 0;
151401a344a2SDavid du Colombier 		f_clunk(cp, in, ou);	/* sets tag, fid */
151501a344a2SDavid du Colombier 		ou->err = er;
151601a344a2SDavid du Colombier 	}
151701a344a2SDavid du Colombier 	/*
151801a344a2SDavid du Colombier 	 * non error
151901a344a2SDavid du Colombier 	 * return newfid
152001a344a2SDavid du Colombier 	 */
152101a344a2SDavid du Colombier }
152201a344a2SDavid du Colombier 
152301a344a2SDavid du Colombier void (*call9p1[MAXSYSCALL])(Chan*, Fcall*, Fcall*) =
152401a344a2SDavid du Colombier {
152501a344a2SDavid du Colombier 	[Tnop]		f_nop,
152601a344a2SDavid du Colombier 	[Tosession]	f_session,
152701a344a2SDavid du Colombier 	[Tsession]	f_session,
152801a344a2SDavid du Colombier 	[Tflush]	f_flush,
152901a344a2SDavid du Colombier 	[Toattach]	f_attach,
153001a344a2SDavid du Colombier 	[Tattach]	f_attach,
153101a344a2SDavid du Colombier 	[Tclone]	f_clone,
153201a344a2SDavid du Colombier 	[Twalk]		f_walk,
153301a344a2SDavid du Colombier 	[Topen]		f_open,
153401a344a2SDavid du Colombier 	[Tcreate]	f_create,
153501a344a2SDavid du Colombier 	[Tread]		f_read,
153601a344a2SDavid du Colombier 	[Twrite]	f_write,
153701a344a2SDavid du Colombier 	[Tclunk]	f_clunk,
153801a344a2SDavid du Colombier 	[Tremove]	f_remove,
153901a344a2SDavid du Colombier 	[Tstat]		f_stat,
154001a344a2SDavid du Colombier 	[Twstat]	f_wstat,
154101a344a2SDavid du Colombier 	[Tclwalk]	f_clwalk,
154201a344a2SDavid du Colombier };
154301a344a2SDavid du Colombier 
154401a344a2SDavid du Colombier int
error9p1(Chan * cp,Msgbuf * mb)154501a344a2SDavid du Colombier error9p1(Chan* cp, Msgbuf* mb)
154601a344a2SDavid du Colombier {
154701a344a2SDavid du Colombier 	Msgbuf *mb1;
154801a344a2SDavid du Colombier 
154901a344a2SDavid du Colombier 	print("type=%d count=%d\n", mb->data[0], mb->count);
155001a344a2SDavid du Colombier 	print(" %.2x %.2x %.2x %.2x\n",
155101a344a2SDavid du Colombier 		mb->data[1]&0xff, mb->data[2]&0xff,
155201a344a2SDavid du Colombier 		mb->data[3]&0xff, mb->data[4]&0xff);
155301a344a2SDavid du Colombier 	print(" %.2x %.2x %.2x %.2x\n",
155401a344a2SDavid du Colombier 		mb->data[5]&0xff, mb->data[6]&0xff,
155501a344a2SDavid du Colombier 		mb->data[7]&0xff, mb->data[8]&0xff);
155601a344a2SDavid du Colombier 	print(" %.2x %.2x %.2x %.2x\n",
155701a344a2SDavid du Colombier 		mb->data[9]&0xff, mb->data[10]&0xff,
155801a344a2SDavid du Colombier 		mb->data[11]&0xff, mb->data[12]&0xff);
155901a344a2SDavid du Colombier 
156001a344a2SDavid du Colombier 	mb1 = mballoc(3, cp, Mbreply4);
156101a344a2SDavid du Colombier 	mb1->data[0] = Rnop;	/* your nop was ok */
156201a344a2SDavid du Colombier 	mb1->data[1] = ~0;
156301a344a2SDavid du Colombier 	mb1->data[2] = ~0;
156401a344a2SDavid du Colombier 	mb1->count = 3;
156501a344a2SDavid du Colombier 	mb1->param = mb->param;
156601a344a2SDavid du Colombier 	fs_send(cp->reply, mb1);
156701a344a2SDavid du Colombier 
156801a344a2SDavid du Colombier 	return 1;
156901a344a2SDavid du Colombier }
157001a344a2SDavid du Colombier 
157101a344a2SDavid du Colombier int
serve9p1(Msgbuf * mb)157201a344a2SDavid du Colombier serve9p1(Msgbuf* mb)
157301a344a2SDavid du Colombier {
157401a344a2SDavid du Colombier 	int t, n;
157501a344a2SDavid du Colombier 	Chan *cp;
157601a344a2SDavid du Colombier 	Msgbuf *mb1;
157701a344a2SDavid du Colombier 	Fcall fi, fo;
157801a344a2SDavid du Colombier 
157901a344a2SDavid du Colombier 	assert(mb != nil);
158001a344a2SDavid du Colombier 	cp = mb->chan;
158101a344a2SDavid du Colombier 	assert(mb->data != nil);
158201a344a2SDavid du Colombier 	if(convM2S9p1(mb->data, &fi, mb->count) == 0){
158301a344a2SDavid du Colombier 		assert(cp != nil);
158401a344a2SDavid du Colombier 		if(cp->protocol == nil)
158501a344a2SDavid du Colombier 			return 0;
158601a344a2SDavid du Colombier 		print("9p1: bad M2S conversion\n");
158701a344a2SDavid du Colombier 		return error9p1(cp, mb);
158801a344a2SDavid du Colombier 	}
158901a344a2SDavid du Colombier 
159001a344a2SDavid du Colombier 	t = fi.type;
159101a344a2SDavid du Colombier 	if(t < 0 || t >= MAXSYSCALL || (t&1) || !call9p1[t]) {
159201a344a2SDavid du Colombier 		print("9p1: bad message type\n");
159301a344a2SDavid du Colombier 		return error9p1(cp, mb);
159401a344a2SDavid du Colombier 	}
159501a344a2SDavid du Colombier 
159601a344a2SDavid du Colombier 	/*
159701a344a2SDavid du Colombier 	 * allocate reply message
159801a344a2SDavid du Colombier 	 */
159901a344a2SDavid du Colombier 	if(t == Tread) {
160001a344a2SDavid du Colombier 		mb1 = mballoc(MAXMSG+MAXDAT, cp, Mbreply2);
160101a344a2SDavid du Colombier 		fo.data = (char*)(mb1->data + 8);
160201a344a2SDavid du Colombier 	} else
160301a344a2SDavid du Colombier 		mb1 = mballoc(MAXMSG, cp, Mbreply3);
160401a344a2SDavid du Colombier 
160501a344a2SDavid du Colombier 	/*
160601a344a2SDavid du Colombier 	 * call the file system
160701a344a2SDavid du Colombier 	 */
160801a344a2SDavid du Colombier 	assert(cp != nil);
160901a344a2SDavid du Colombier 	fo.err = 0;
161001a344a2SDavid du Colombier 
161101a344a2SDavid du Colombier 	(*call9p1[t])(cp, &fi, &fo);
161201a344a2SDavid du Colombier 
161301a344a2SDavid du Colombier 	fo.type = t+1;
161401a344a2SDavid du Colombier 	fo.tag = fi.tag;
161501a344a2SDavid du Colombier 
161601a344a2SDavid du Colombier 	if(fo.err) {
161701a344a2SDavid du Colombier 		if(cons.flags&errorflag)
161801a344a2SDavid du Colombier 			print("\ttype %d: error: %s\n", t, errstr9p[fo.err]);
161901a344a2SDavid du Colombier 		if(CHAT(cp))
162001a344a2SDavid du Colombier 			print("\terror: %s\n", errstr9p[fo.err]);
162101a344a2SDavid du Colombier 		fo.type = Rerror;
162201a344a2SDavid du Colombier 		strncpy(fo.ename, errstr9p[fo.err], sizeof(fo.ename));
162301a344a2SDavid du Colombier 	}
162401a344a2SDavid du Colombier 
162501a344a2SDavid du Colombier 	n = convS2M9p1(&fo, mb1->data);
162601a344a2SDavid du Colombier 	if(n == 0) {
162701a344a2SDavid du Colombier 		print("9p1: bad S2M conversion\n");
162801a344a2SDavid du Colombier 		mbfree(mb1);
162901a344a2SDavid du Colombier 		return error9p1(cp, mb);
163001a344a2SDavid du Colombier 	}
163101a344a2SDavid du Colombier 	mb1->count = n;
163201a344a2SDavid du Colombier 	mb1->param = mb->param;
163301a344a2SDavid du Colombier 	fs_send(cp->reply, mb1);
163401a344a2SDavid du Colombier 
163501a344a2SDavid du Colombier 	return 1;
163601a344a2SDavid du Colombier }
1637