xref: /plan9/sys/src/cmd/disk/kfs/9p1.c (revision 229d2d344532463b8438213e6bf550fed5babd4a)
19a747e4fSDavid du Colombier #include	"all.h"
29a747e4fSDavid du Colombier #include	"9p1.h"
39a747e4fSDavid du Colombier 
49a747e4fSDavid du Colombier /*
59a747e4fSDavid du Colombier  * buggery to give false qid for
69a747e4fSDavid du Colombier  * the top 2 levels of the dump fs
79a747e4fSDavid du Colombier  */
89a747e4fSDavid du Colombier void
mkqid(Qid * qid,Dentry * d,int buggery)99a747e4fSDavid du Colombier mkqid(Qid* qid, Dentry *d, int buggery)
109a747e4fSDavid du Colombier {
119a747e4fSDavid du Colombier 	int c;
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier 	if(buggery && d->qid.path == QPROOT && (d->qid.path & QPDIR)){
149a747e4fSDavid du Colombier 		c = d->name[0];
159a747e4fSDavid du Colombier 		if(c >= '0' && c <= '9'){
169a747e4fSDavid du Colombier 			qid->path = 3;
179a747e4fSDavid du Colombier 			qid->vers = d->qid.version;
189a747e4fSDavid du Colombier 			qid->type = QTDIR;
199a747e4fSDavid du Colombier 
209a747e4fSDavid du Colombier 			c = (c-'0')*10 + (d->name[1]-'0');
219a747e4fSDavid du Colombier 			if(c >= 1 && c <= 12)
229a747e4fSDavid du Colombier 				qid->path = 4;
239a747e4fSDavid du Colombier 			return;
249a747e4fSDavid du Colombier 		}
259a747e4fSDavid du Colombier 	}
269a747e4fSDavid du Colombier 
279a747e4fSDavid du Colombier 	mkqid9p2(qid, &d->qid, d->mode);
289a747e4fSDavid du Colombier }
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier int
mkqidcmp(Qid * qid,Dentry * d)319a747e4fSDavid du Colombier mkqidcmp(Qid* qid, Dentry *d)
329a747e4fSDavid du Colombier {
339a747e4fSDavid du Colombier 	Qid tmp;
349a747e4fSDavid du Colombier 
359a747e4fSDavid du Colombier 	mkqid(&tmp, d, 1);
369a747e4fSDavid du Colombier 	if(qid->path==tmp.path && (qid->type&QTDIR)==(tmp.type&QTDIR))
379a747e4fSDavid du Colombier 		return 0;
389a747e4fSDavid du Colombier 	return Eqid;
399a747e4fSDavid du Colombier }
409a747e4fSDavid du Colombier 
419a747e4fSDavid du Colombier void
f_nop(Chan * cp,Oldfcall * in,Oldfcall * ou)429a747e4fSDavid du Colombier f_nop(Chan *cp, Oldfcall *in, Oldfcall *ou)
439a747e4fSDavid du Colombier {
449a747e4fSDavid du Colombier 
459a747e4fSDavid du Colombier 	USED(in);
469a747e4fSDavid du Colombier 	USED(ou);
479a747e4fSDavid du Colombier 	if(CHAT(cp))
489a747e4fSDavid du Colombier 		print("c_nop %d\n", cp->chan);
499a747e4fSDavid du Colombier }
509a747e4fSDavid du Colombier 
519a747e4fSDavid du Colombier void
f_flush(Chan * cp,Oldfcall * in,Oldfcall * ou)529a747e4fSDavid du Colombier f_flush(Chan *cp, Oldfcall *in, Oldfcall *ou)
539a747e4fSDavid du Colombier {
549a747e4fSDavid du Colombier 
559a747e4fSDavid du Colombier 	USED(in);
569a747e4fSDavid du Colombier 	USED(ou);
579a747e4fSDavid du Colombier 	if(CHAT(cp))
589a747e4fSDavid du Colombier 		print("c_flush %d\n", cp->chan);
599a747e4fSDavid du Colombier 	runlock(&cp->reflock);
609a747e4fSDavid du Colombier 	wlock(&cp->reflock);
619a747e4fSDavid du Colombier 	wunlock(&cp->reflock);
629a747e4fSDavid du Colombier 	rlock(&cp->reflock);
639a747e4fSDavid du Colombier }
649a747e4fSDavid du Colombier 
659a747e4fSDavid du Colombier void
f_session(Chan * cp,Oldfcall * in,Oldfcall * ou)669a747e4fSDavid du Colombier f_session(Chan *cp, Oldfcall *in, Oldfcall *ou)
679a747e4fSDavid du Colombier {
689a747e4fSDavid du Colombier 	if(CHAT(cp))
699a747e4fSDavid du Colombier 		print("c_session %d\n", cp->chan);
709a747e4fSDavid du Colombier 
719a747e4fSDavid du Colombier 	memmove(cp->rchal, in->chal, sizeof(cp->rchal));
725d459b5aSDavid du Colombier 	if(wstatallow || cp == cons.srvchan){
73d9306527SDavid du Colombier 		memset(ou->chal, 0, sizeof(ou->chal));
749a747e4fSDavid du Colombier 		memset(ou->authid, 0, sizeof(ou->authid));
755d459b5aSDavid du Colombier 	}else{
765d459b5aSDavid du Colombier 		mkchallenge(cp);
77d9306527SDavid du Colombier 		memmove(ou->chal, cp->chal, sizeof(ou->chal));
789a747e4fSDavid du Colombier 		memmove(ou->authid, nvr.authid, sizeof(ou->authid));
795d459b5aSDavid du Colombier 	}
809a747e4fSDavid du Colombier 	sprint(ou->authdom, "%s.%s", service, nvr.authdom);
819a747e4fSDavid du Colombier 	fileinit(cp);
829a747e4fSDavid du Colombier }
839a747e4fSDavid du Colombier 
849a747e4fSDavid du Colombier void
f_attach(Chan * cp,Oldfcall * in,Oldfcall * ou)859a747e4fSDavid du Colombier f_attach(Chan *cp, Oldfcall *in, Oldfcall *ou)
869a747e4fSDavid du Colombier {
879a747e4fSDavid du Colombier 	Iobuf *p;
889a747e4fSDavid du Colombier 	Dentry *d;
899a747e4fSDavid du Colombier 	File *f;
909a747e4fSDavid du Colombier 	int u;
919a747e4fSDavid du Colombier 	Filsys *fs;
929a747e4fSDavid du Colombier 	long raddr;
939a747e4fSDavid du Colombier 
949a747e4fSDavid du Colombier 	if(CHAT(cp)) {
959a747e4fSDavid du Colombier 		print("c_attach %d\n", cp->chan);
969a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
979a747e4fSDavid du Colombier 		print("	uid = %s\n", in->uname);
989a747e4fSDavid du Colombier 		print("	arg = %s\n", in->aname);
999a747e4fSDavid du Colombier 	}
1009a747e4fSDavid du Colombier 
1019a747e4fSDavid du Colombier 	ou->qid = QID9P1(0,0);
1029a747e4fSDavid du Colombier 	ou->fid = in->fid;
1039a747e4fSDavid du Colombier 	if(!in->aname[0])	/* default */
1049a747e4fSDavid du Colombier 		strncpy(in->aname, filesys[0].name, sizeof(in->aname));
1059a747e4fSDavid du Colombier 	p = 0;
1069a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 1);
1079a747e4fSDavid du Colombier 	if(!f) {
1089a747e4fSDavid du Colombier 		ou->err = Efid;
1099a747e4fSDavid du Colombier 		goto out;
1109a747e4fSDavid du Colombier 	}
1119a747e4fSDavid du Colombier 	u = -1;
1129a747e4fSDavid du Colombier 	if(cp != cons.chan){
1135d459b5aSDavid du Colombier 		if(authorize(cp, in, ou) == 0 || strcmp(in->uname, "adm") == 0){
1149a747e4fSDavid du Colombier 			ou->err = Eauth;
1159a747e4fSDavid du Colombier 			goto out;
1169a747e4fSDavid du Colombier 		}
1179a747e4fSDavid du Colombier 		u = strtouid(in->uname);
1189a747e4fSDavid du Colombier 		if(u < 0){
1199a747e4fSDavid du Colombier 			ou->err = Ebadu;
1209a747e4fSDavid du Colombier 			goto out;
1219a747e4fSDavid du Colombier 		}
1229a747e4fSDavid du Colombier 	}
1239a747e4fSDavid du Colombier 
1249a747e4fSDavid du Colombier 	fs = fsstr(in->aname);
1259a747e4fSDavid du Colombier 	if(fs == 0) {
1269a747e4fSDavid du Colombier 		ou->err = Ebadspc;
1279a747e4fSDavid du Colombier 		goto out;
1289a747e4fSDavid du Colombier 	}
1299a747e4fSDavid du Colombier 	raddr = getraddr(fs->dev);
1309a747e4fSDavid du Colombier 	p = getbuf(fs->dev, raddr, Bread);
1319a747e4fSDavid du Colombier 	d = getdir(p, 0);
1329a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) {
1339a747e4fSDavid du Colombier 		ou->err = Ealloc;
1349a747e4fSDavid du Colombier 		goto out;
1359a747e4fSDavid du Colombier 	}
1369a747e4fSDavid du Colombier 	f->uid = u;
1379a747e4fSDavid du Colombier 	if(iaccess(f, d, DREAD)) {
1389a747e4fSDavid du Colombier 		ou->err = Eaccess;
1399a747e4fSDavid du Colombier 		goto out;
1409a747e4fSDavid du Colombier 	}
1419a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
1429a747e4fSDavid du Colombier 	mkqid(&f->qid, d, 1);
1439a747e4fSDavid du Colombier 	f->fs = fs;
1449a747e4fSDavid du Colombier 	f->addr = raddr;
1459a747e4fSDavid du Colombier 	f->slot = 0;
1469a747e4fSDavid du Colombier 	f->open = 0;
1479a747e4fSDavid du Colombier 	freewp(f->wpath);
1489a747e4fSDavid du Colombier 	f->wpath = 0;
1499a747e4fSDavid du Colombier 
1509a747e4fSDavid du Colombier 	mkqid9p1(&ou->qid, &f->qid);
1519a747e4fSDavid du Colombier 
1529a747e4fSDavid du Colombier out:
1539a747e4fSDavid du Colombier 	if(p)
1549a747e4fSDavid du Colombier 		putbuf(p);
1559a747e4fSDavid du Colombier 	if(f) {
1569a747e4fSDavid du Colombier 		qunlock(f);
1579a747e4fSDavid du Colombier 		if(ou->err)
1589a747e4fSDavid du Colombier 			freefp(f);
1599a747e4fSDavid du Colombier 	}
1609a747e4fSDavid du Colombier }
1619a747e4fSDavid du Colombier 
1629a747e4fSDavid du Colombier void
f_clone(Chan * cp,Oldfcall * in,Oldfcall * ou)1639a747e4fSDavid du Colombier f_clone(Chan *cp, Oldfcall *in, Oldfcall *ou)
1649a747e4fSDavid du Colombier {
1659a747e4fSDavid du Colombier 	File *f1, *f2;
1669a747e4fSDavid du Colombier 	int fid, fid1;
1679a747e4fSDavid du Colombier 
1689a747e4fSDavid du Colombier 	if(CHAT(cp)) {
1699a747e4fSDavid du Colombier 		print("c_clone %d\n", cp->chan);
1709a747e4fSDavid du Colombier 		print("	old fid = %d\n", in->fid);
1719a747e4fSDavid du Colombier 		print("	new fid = %d\n", in->newfid);
1729a747e4fSDavid du Colombier 	}
1739a747e4fSDavid du Colombier 
1749a747e4fSDavid du Colombier 	fid = in->fid;
1759a747e4fSDavid du Colombier 	fid1 = in->newfid;
1769a747e4fSDavid du Colombier 
1779a747e4fSDavid du Colombier 	f1 = 0;
1789a747e4fSDavid du Colombier 	f2 = 0;
1799a747e4fSDavid du Colombier 	if(fid < fid1) {
1809a747e4fSDavid du Colombier 		f1 = filep(cp, fid, 0);
1819a747e4fSDavid du Colombier 		f2 = filep(cp, fid1, 1);
1829a747e4fSDavid du Colombier 	} else
1839a747e4fSDavid du Colombier 	if(fid1 < fid) {
1849a747e4fSDavid du Colombier 		f2 = filep(cp, fid1, 1);
1859a747e4fSDavid du Colombier 		f1 = filep(cp, fid, 0);
1869a747e4fSDavid du Colombier 	}
1879a747e4fSDavid du Colombier 	if(!f1 || !f2) {
1889a747e4fSDavid du Colombier 		ou->err = Efid;
1899a747e4fSDavid du Colombier 		goto out;
1909a747e4fSDavid du Colombier 	}
1919a747e4fSDavid du Colombier 
1929a747e4fSDavid du Colombier 
1939a747e4fSDavid du Colombier 	f2->fs = f1->fs;
1949a747e4fSDavid du Colombier 	f2->addr = f1->addr;
1959a747e4fSDavid du Colombier 	f2->open = f1->open & ~FREMOV;
1969a747e4fSDavid du Colombier 	f2->uid = f1->uid;
1979a747e4fSDavid du Colombier 	f2->slot = f1->slot;
1989a747e4fSDavid du Colombier 	f2->qid = f1->qid;
1999a747e4fSDavid du Colombier 
2009a747e4fSDavid du Colombier 	freewp(f2->wpath);
2019a747e4fSDavid du Colombier 	f2->wpath = getwp(f1->wpath);
2029a747e4fSDavid du Colombier 
2039a747e4fSDavid du Colombier out:
2049a747e4fSDavid du Colombier 	ou->fid = fid;
2059a747e4fSDavid du Colombier 	if(f1)
2069a747e4fSDavid du Colombier 		qunlock(f1);
2079a747e4fSDavid du Colombier 	if(f2)
2089a747e4fSDavid du Colombier 		qunlock(f2);
2099a747e4fSDavid du Colombier }
2109a747e4fSDavid du Colombier 
2119a747e4fSDavid du Colombier void
f_walk(Chan * cp,Oldfcall * in,Oldfcall * ou)2129a747e4fSDavid du Colombier f_walk(Chan *cp, Oldfcall *in, Oldfcall *ou)
2139a747e4fSDavid du Colombier {
2149a747e4fSDavid du Colombier 	Iobuf *p, *p1;
2159a747e4fSDavid du Colombier 	Dentry *d, *d1;
2169a747e4fSDavid du Colombier 	File *f;
2179a747e4fSDavid du Colombier 	Wpath *w, *ow;
2189a747e4fSDavid du Colombier 	int slot;
2199a747e4fSDavid du Colombier 	long addr;
2209a747e4fSDavid du Colombier 
2219a747e4fSDavid du Colombier 	if(CHAT(cp)) {
2229a747e4fSDavid du Colombier 		print("c_walk %d\n", cp->chan);
2239a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
2249a747e4fSDavid du Colombier 		print("	name = %s\n", in->name);
2259a747e4fSDavid du Colombier 	}
2269a747e4fSDavid du Colombier 
2279a747e4fSDavid du Colombier 	ou->fid = in->fid;
2289a747e4fSDavid du Colombier 	ou->qid = QID9P1(0,0);
2299a747e4fSDavid du Colombier 	p = 0;
2309a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
2319a747e4fSDavid du Colombier 	if(!f) {
2329a747e4fSDavid du Colombier 		ou->err = Efid;
2339a747e4fSDavid du Colombier 		goto out;
2349a747e4fSDavid du Colombier 	}
2359a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
2369a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
2379a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
2389a747e4fSDavid du Colombier 		ou->err = Ealloc;
2399a747e4fSDavid du Colombier 		goto out;
2409a747e4fSDavid du Colombier 	}
2419a747e4fSDavid du Colombier 	if(!(d->mode & DDIR)) {
2429a747e4fSDavid du Colombier 		ou->err = Edir1;
2439a747e4fSDavid du Colombier 		goto out;
2449a747e4fSDavid du Colombier 	}
2459a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
2469a747e4fSDavid du Colombier 		goto out;
2479a747e4fSDavid du Colombier 	if(cp != cons.chan && iaccess(f, d, DEXEC)) {
2489a747e4fSDavid du Colombier 		ou->err = Eaccess;
2499a747e4fSDavid du Colombier 		goto out;
2509a747e4fSDavid du Colombier 	}
2519a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
2529a747e4fSDavid du Colombier 	if(strcmp(in->name, ".") == 0)
2539a747e4fSDavid du Colombier 		goto setdot;
2549a747e4fSDavid du Colombier 	if(strcmp(in->name, "..") == 0) {
2559a747e4fSDavid du Colombier 		if(f->wpath == 0)
2569a747e4fSDavid du Colombier 			goto setdot;
2579a747e4fSDavid du Colombier 		putbuf(p);
2589a747e4fSDavid du Colombier 		p = 0;
2599a747e4fSDavid du Colombier 		addr = f->wpath->addr;
2609a747e4fSDavid du Colombier 		slot = f->wpath->slot;
2619a747e4fSDavid du Colombier 		p1 = getbuf(f->fs->dev, addr, Bread);
2629a747e4fSDavid du Colombier 		d1 = getdir(p1, slot);
2639a747e4fSDavid du Colombier 		if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
2649a747e4fSDavid du Colombier 			if(p1)
2659a747e4fSDavid du Colombier 				putbuf(p1);
2669a747e4fSDavid du Colombier 			ou->err = Ephase;
2679a747e4fSDavid du Colombier 			goto out;
2689a747e4fSDavid du Colombier 		}
2699a747e4fSDavid du Colombier 		ow = f->wpath;
2709a747e4fSDavid du Colombier 		f->wpath = ow->up;
2719a747e4fSDavid du Colombier 		putwp(ow);
2729a747e4fSDavid du Colombier 		goto found;
2739a747e4fSDavid du Colombier 	}
2749a747e4fSDavid du Colombier 	for(addr=0;; addr++) {
2759a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0);
2769a747e4fSDavid du Colombier 		if(!p1 || checktag(p1, Tdir, d->qid.path) ) {
2779a747e4fSDavid du Colombier 			if(p1)
2789a747e4fSDavid du Colombier 				putbuf(p1);
2799a747e4fSDavid du Colombier 			ou->err = Eentry;
2809a747e4fSDavid du Colombier 			goto out;
2819a747e4fSDavid du Colombier 		}
2829a747e4fSDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
2839a747e4fSDavid du Colombier 			d1 = getdir(p1, slot);
2849a747e4fSDavid du Colombier 			if(!(d1->mode & DALLOC))
2859a747e4fSDavid du Colombier 				continue;
2869a747e4fSDavid du Colombier 			if(strncmp(in->name, d1->name, sizeof(in->name)))
2879a747e4fSDavid du Colombier 				continue;
2889a747e4fSDavid du Colombier 			/*
2899a747e4fSDavid du Colombier 			 * update walk path
2909a747e4fSDavid du Colombier 			 */
2919a747e4fSDavid du Colombier 			w = newwp();
2929a747e4fSDavid du Colombier 			if(!w) {
2939a747e4fSDavid du Colombier 				ou->err = Ewalk;
2949a747e4fSDavid du Colombier 				putbuf(p1);
2959a747e4fSDavid du Colombier 				goto out;
2969a747e4fSDavid du Colombier 			}
2979a747e4fSDavid du Colombier 			w->addr = f->addr;
2989a747e4fSDavid du Colombier 			w->slot = f->slot;
2999a747e4fSDavid du Colombier 			w->up = f->wpath;
3009a747e4fSDavid du Colombier 			f->wpath = w;
3019a747e4fSDavid du Colombier 			slot += DIRPERBUF*addr;
3029a747e4fSDavid du Colombier 			goto found;
3039a747e4fSDavid du Colombier 		}
3049a747e4fSDavid du Colombier 		putbuf(p1);
3059a747e4fSDavid du Colombier 	}
3069a747e4fSDavid du Colombier 
3079a747e4fSDavid du Colombier found:
3089a747e4fSDavid du Colombier 	f->addr = p1->addr;
3099a747e4fSDavid du Colombier 	mkqid(&f->qid, d1, 1);
3109a747e4fSDavid du Colombier 	putbuf(p1);
3119a747e4fSDavid du Colombier 	f->slot = slot;
3129a747e4fSDavid du Colombier 
3139a747e4fSDavid du Colombier setdot:
3149a747e4fSDavid du Colombier 	mkqid9p1(&ou->qid, &f->qid);
3159a747e4fSDavid du Colombier 	f->open = 0;
3169a747e4fSDavid du Colombier 
3179a747e4fSDavid du Colombier out:
3189a747e4fSDavid du Colombier 	if(p)
3199a747e4fSDavid du Colombier 		putbuf(p);
3209a747e4fSDavid du Colombier 	if(f)
3219a747e4fSDavid du Colombier 		qunlock(f);
3229a747e4fSDavid du Colombier }
3239a747e4fSDavid du Colombier 
3249a747e4fSDavid du Colombier void
f_clunk(Chan * cp,Oldfcall * in,Oldfcall * ou)3259a747e4fSDavid du Colombier f_clunk(Chan *cp, Oldfcall *in, Oldfcall *ou)
3269a747e4fSDavid du Colombier {
3279a747e4fSDavid du Colombier 	File *f;
3289a747e4fSDavid du Colombier 	Tlock *t;
3299a747e4fSDavid du Colombier 	long tim;
3309a747e4fSDavid du Colombier 
3319a747e4fSDavid du Colombier 	if(CHAT(cp)) {
3329a747e4fSDavid du Colombier 		print("c_clunk %d\n", cp->chan);
3339a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
3349a747e4fSDavid du Colombier 	}
3359a747e4fSDavid du Colombier 
3369a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
3379a747e4fSDavid du Colombier 	if(!f) {
3389a747e4fSDavid du Colombier 		print("%p\n", f);
3399a747e4fSDavid du Colombier 		ou->err = Efid;
3409a747e4fSDavid du Colombier 		goto out;
3419a747e4fSDavid du Colombier 	}
3429a747e4fSDavid du Colombier 	if(t = f->tlock) {
3439a747e4fSDavid du Colombier 		tim = time(0);
3449a747e4fSDavid du Colombier 		if(t->time < tim || t->file != f)
3459a747e4fSDavid du Colombier 			ou->err = Ebroken;
3469a747e4fSDavid du Colombier 		t->time = 0;	/* free the lock */
3479a747e4fSDavid du Colombier 		f->tlock = 0;
3489a747e4fSDavid du Colombier 	}
3499a747e4fSDavid du Colombier 	if(f->open & FREMOV)
3509a747e4fSDavid du Colombier 		ou->err = doremove(f, 0);
3519a747e4fSDavid du Colombier 	f->open = 0;
3529a747e4fSDavid du Colombier 	freewp(f->wpath);
3539a747e4fSDavid du Colombier 	freefp(f);
3549a747e4fSDavid du Colombier 
3559a747e4fSDavid du Colombier out:
3569a747e4fSDavid du Colombier 	if(f)
3579a747e4fSDavid du Colombier 		qunlock(f);
3589a747e4fSDavid du Colombier 	ou->fid = in->fid;
3599a747e4fSDavid du Colombier }
3609a747e4fSDavid du Colombier 
3619a747e4fSDavid du Colombier void
f_clwalk(Chan * cp,Oldfcall * in,Oldfcall * ou)3629a747e4fSDavid du Colombier f_clwalk(Chan *cp, Oldfcall *in, Oldfcall *ou)
3639a747e4fSDavid du Colombier {
3649a747e4fSDavid du Colombier 	int er, fid;
3659a747e4fSDavid du Colombier 
3669a747e4fSDavid du Colombier 	if(CHAT(cp))
3679a747e4fSDavid du Colombier 		print("c_clwalk macro\n");
3689a747e4fSDavid du Colombier 
3699a747e4fSDavid du Colombier 	f_clone(cp, in, ou);		/* sets tag, fid */
3709a747e4fSDavid du Colombier 	if(ou->err)
3719a747e4fSDavid du Colombier 		return;
3729a747e4fSDavid du Colombier 	fid = in->fid;
3739a747e4fSDavid du Colombier 	in->fid = in->newfid;
3749a747e4fSDavid du Colombier 	f_walk(cp, in, ou);		/* sets tag, fid, qid */
3759a747e4fSDavid du Colombier 	er = ou->err;
3769a747e4fSDavid du Colombier 	if(er == Eentry) {
3779a747e4fSDavid du Colombier 		/*
3789a747e4fSDavid du Colombier 		 * if error is "no entry"
3799a747e4fSDavid du Colombier 		 * return non error and fid
3809a747e4fSDavid du Colombier 		 */
3819a747e4fSDavid du Colombier 		ou->err = 0;
3829a747e4fSDavid du Colombier 		f_clunk(cp, in, ou);	/* sets tag, fid */
3839a747e4fSDavid du Colombier 		ou->err = 0;
3849a747e4fSDavid du Colombier 		ou->fid = fid;
3859a747e4fSDavid du Colombier 		if(CHAT(cp))
3869a747e4fSDavid du Colombier 			print("	error: %s\n", errstring[er]);
3879a747e4fSDavid du Colombier 		return;
3889a747e4fSDavid du Colombier 	}
3899a747e4fSDavid du Colombier 	if(er) {
3909a747e4fSDavid du Colombier 		/*
3919a747e4fSDavid du Colombier 		 * if any other error
3929a747e4fSDavid du Colombier 		 * return an error
3939a747e4fSDavid du Colombier 		 */
3949a747e4fSDavid du Colombier 		ou->err = 0;
3959a747e4fSDavid du Colombier 		f_clunk(cp, in, ou);	/* sets tag, fid */
3969a747e4fSDavid du Colombier 		ou->err = er;
3979a747e4fSDavid du Colombier 		return;
3989a747e4fSDavid du Colombier 	}
3999a747e4fSDavid du Colombier 	/*
4009a747e4fSDavid du Colombier 	 * non error
4019a747e4fSDavid du Colombier 	 * return newfid
4029a747e4fSDavid du Colombier 	 */
4039a747e4fSDavid du Colombier }
4049a747e4fSDavid du Colombier 
4059a747e4fSDavid du Colombier void
f_open(Chan * cp,Oldfcall * in,Oldfcall * ou)4069a747e4fSDavid du Colombier f_open(Chan *cp, Oldfcall *in, Oldfcall *ou)
4079a747e4fSDavid du Colombier {
4089a747e4fSDavid du Colombier 	Iobuf *p;
4099a747e4fSDavid du Colombier 	Dentry *d;
4109a747e4fSDavid du Colombier 	File *f;
4119a747e4fSDavid du Colombier 	Tlock *t;
4129a747e4fSDavid du Colombier 	Qid qid;
4139a747e4fSDavid du Colombier 	int ro, fmod;
4149a747e4fSDavid du Colombier 
4159a747e4fSDavid du Colombier 	if(CHAT(cp)) {
4169a747e4fSDavid du Colombier 		print("c_open %d\n", cp->chan);
4179a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
4189a747e4fSDavid du Colombier 		print("	mode = %o\n", in->mode);
4199a747e4fSDavid du Colombier 	}
4209a747e4fSDavid du Colombier 
4219a747e4fSDavid du Colombier 	p = 0;
4229a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
4239a747e4fSDavid du Colombier 	if(!f) {
4249a747e4fSDavid du Colombier 		ou->err = Efid;
4259a747e4fSDavid du Colombier 		goto out;
4269a747e4fSDavid du Colombier 	}
4279a747e4fSDavid du Colombier 
4289a747e4fSDavid du Colombier 	/*
4299a747e4fSDavid du Colombier 	 * if remove on close, check access here
4309a747e4fSDavid du Colombier 	 */
4315d459b5aSDavid du Colombier 	ro = isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup));
4329a747e4fSDavid du Colombier 	if(in->mode & MRCLOSE) {
4339a747e4fSDavid du Colombier 		if(ro) {
4349a747e4fSDavid du Colombier 			ou->err = Eronly;
4359a747e4fSDavid du Colombier 			goto out;
4369a747e4fSDavid du Colombier 		}
4379a747e4fSDavid du Colombier 		/*
4389a747e4fSDavid du Colombier 		 * check on parent directory of file to be deleted
4399a747e4fSDavid du Colombier 		 */
4409a747e4fSDavid du Colombier 		if(f->wpath == 0 || f->wpath->addr == f->addr) {
4419a747e4fSDavid du Colombier 			ou->err = Ephase;
4429a747e4fSDavid du Colombier 			goto out;
4439a747e4fSDavid du Colombier 		}
4449a747e4fSDavid du Colombier 		p = getbuf(f->fs->dev, f->wpath->addr, Bread);
4459a747e4fSDavid du Colombier 		d = getdir(p, f->wpath->slot);
4469a747e4fSDavid du Colombier 		if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
4479a747e4fSDavid du Colombier 			ou->err = Ephase;
4489a747e4fSDavid du Colombier 			goto out;
4499a747e4fSDavid du Colombier 		}
4509a747e4fSDavid du Colombier 		if(iaccess(f, d, DWRITE)) {
4519a747e4fSDavid du Colombier 			ou->err = Eaccess;
4529a747e4fSDavid du Colombier 			goto out;
4539a747e4fSDavid du Colombier 		}
4549a747e4fSDavid du Colombier 		putbuf(p);
4559a747e4fSDavid du Colombier 	}
4569a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
4579a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
4589a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
4599a747e4fSDavid du Colombier 		ou->err = Ealloc;
4609a747e4fSDavid du Colombier 		goto out;
4619a747e4fSDavid du Colombier 	}
4629a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
4639a747e4fSDavid du Colombier 		goto out;
4649a747e4fSDavid du Colombier 	mkqid(&qid, d, 1);
4659a747e4fSDavid du Colombier 	switch(in->mode & 7) {
4669a747e4fSDavid du Colombier 
4679a747e4fSDavid du Colombier 	case MREAD:
4689a747e4fSDavid du Colombier 		if(iaccess(f, d, DREAD) && !writeallow)
4699a747e4fSDavid du Colombier 			goto badaccess;
4709a747e4fSDavid du Colombier 		fmod = FREAD;
4719a747e4fSDavid du Colombier 		break;
4729a747e4fSDavid du Colombier 
4739a747e4fSDavid du Colombier 	case MWRITE:
4749a747e4fSDavid du Colombier 		if((d->mode & DDIR) ||
4759a747e4fSDavid du Colombier 		   (iaccess(f, d, DWRITE) && !writeallow))
4769a747e4fSDavid du Colombier 			goto badaccess;
4779a747e4fSDavid du Colombier 		if(ro) {
4789a747e4fSDavid du Colombier 			ou->err = Eronly;
4799a747e4fSDavid du Colombier 			goto out;
4809a747e4fSDavid du Colombier 		}
4819a747e4fSDavid du Colombier 		fmod = FWRITE;
4829a747e4fSDavid du Colombier 		break;
4839a747e4fSDavid du Colombier 
4849a747e4fSDavid du Colombier 	case MBOTH:
4859a747e4fSDavid du Colombier 		if((d->mode & DDIR) ||
4869a747e4fSDavid du Colombier 		   (iaccess(f, d, DREAD) && !writeallow) ||
4879a747e4fSDavid du Colombier 		   (iaccess(f, d, DWRITE) && !writeallow))
4889a747e4fSDavid du Colombier 			goto badaccess;
4899a747e4fSDavid du Colombier 		if(ro) {
4909a747e4fSDavid du Colombier 			ou->err = Eronly;
4919a747e4fSDavid du Colombier 			goto out;
4929a747e4fSDavid du Colombier 		}
4939a747e4fSDavid du Colombier 		fmod = FREAD+FWRITE;
4949a747e4fSDavid du Colombier 		break;
4959a747e4fSDavid du Colombier 
4969a747e4fSDavid du Colombier 	case MEXEC:
4979a747e4fSDavid du Colombier 		if((d->mode & DDIR) ||
4989a747e4fSDavid du Colombier 		   iaccess(f, d, DEXEC))
4999a747e4fSDavid du Colombier 			goto badaccess;
5009a747e4fSDavid du Colombier 		fmod = FREAD;
5019a747e4fSDavid du Colombier 		break;
5029a747e4fSDavid du Colombier 
5039a747e4fSDavid du Colombier 	default:
5049a747e4fSDavid du Colombier 		ou->err = Emode;
5059a747e4fSDavid du Colombier 		goto out;
5069a747e4fSDavid du Colombier 	}
5079a747e4fSDavid du Colombier 	if(in->mode & MTRUNC) {
5089a747e4fSDavid du Colombier 		if((d->mode & DDIR) ||
5099a747e4fSDavid du Colombier 		   (iaccess(f, d, DWRITE) && !writeallow))
5109a747e4fSDavid du Colombier 			goto badaccess;
5119a747e4fSDavid du Colombier 		if(ro) {
5129a747e4fSDavid du Colombier 			ou->err = Eronly;
5139a747e4fSDavid du Colombier 			goto out;
5149a747e4fSDavid du Colombier 		}
5159a747e4fSDavid du Colombier 	}
5169a747e4fSDavid du Colombier 	t = 0;
5179a747e4fSDavid du Colombier 	if(d->mode & DLOCK) {
5189a747e4fSDavid du Colombier 		t = tlocked(p, d);
5199a747e4fSDavid du Colombier 		if(t == 0) {
5209a747e4fSDavid du Colombier 			ou->err = Elocked;
5219a747e4fSDavid du Colombier 			goto out;
5229a747e4fSDavid du Colombier 		}
5239a747e4fSDavid du Colombier 		t->file = f;
5249a747e4fSDavid du Colombier 	}
5259a747e4fSDavid du Colombier 	if(in->mode & MRCLOSE)
5269a747e4fSDavid du Colombier 		fmod |= FREMOV;
5279a747e4fSDavid du Colombier 	f->open = fmod;
5289a747e4fSDavid du Colombier 	if(in->mode & MTRUNC)
5299a747e4fSDavid du Colombier 		if(!(d->mode & DAPND))
5309a747e4fSDavid du Colombier 			dtrunc(p, d);
5319a747e4fSDavid du Colombier 	f->tlock = t;
5329a747e4fSDavid du Colombier 	f->lastra = 0;
5339a747e4fSDavid du Colombier 	mkqid9p1(&ou->qid, &qid);
5349a747e4fSDavid du Colombier 	goto out;
5359a747e4fSDavid du Colombier 
5369a747e4fSDavid du Colombier badaccess:
5379a747e4fSDavid du Colombier 	ou->err = Eaccess;
5389a747e4fSDavid du Colombier 	f->open = 0;
5399a747e4fSDavid du Colombier 
5409a747e4fSDavid du Colombier out:
5419a747e4fSDavid du Colombier 	if(p)
5429a747e4fSDavid du Colombier 		putbuf(p);
5439a747e4fSDavid du Colombier 	if(f)
5449a747e4fSDavid du Colombier 		qunlock(f);
5459a747e4fSDavid du Colombier 	ou->fid = in->fid;
5469a747e4fSDavid du Colombier }
5479a747e4fSDavid du Colombier 
5489a747e4fSDavid du Colombier void
f_create(Chan * cp,Oldfcall * in,Oldfcall * ou)5499a747e4fSDavid du Colombier f_create(Chan *cp, Oldfcall *in, Oldfcall *ou)
5509a747e4fSDavid du Colombier {
5519a747e4fSDavid du Colombier 	Iobuf *p, *p1;
5529a747e4fSDavid du Colombier 	Dentry *d, *d1;
5539a747e4fSDavid du Colombier 	File *f;
5549a747e4fSDavid du Colombier 	int slot, slot1, fmod;
5559a747e4fSDavid du Colombier 	long addr, addr1, path;
5569a747e4fSDavid du Colombier 	Qid qid;
5579a747e4fSDavid du Colombier 	Tlock *t;
5589a747e4fSDavid du Colombier 	Wpath *w;
5599a747e4fSDavid du Colombier 
5609a747e4fSDavid du Colombier 	if(CHAT(cp)) {
5619a747e4fSDavid du Colombier 		print("c_create %d\n", cp->chan);
5629a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
5639a747e4fSDavid du Colombier 		print("	name = %s\n", in->name);
5649a747e4fSDavid du Colombier 		print("	perm = %lx+%lo\n", (in->perm>>28)&0xf,
5659a747e4fSDavid du Colombier 				in->perm&0777);
5669a747e4fSDavid du Colombier 		print("	mode = %d\n", in->mode);
5679a747e4fSDavid du Colombier 	}
5689a747e4fSDavid du Colombier 
5699a747e4fSDavid du Colombier 	p = 0;
5709a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
5719a747e4fSDavid du Colombier 	if(!f) {
5729a747e4fSDavid du Colombier 		ou->err = Efid;
5739a747e4fSDavid du Colombier 		goto out;
5749a747e4fSDavid du Colombier 	}
5755d459b5aSDavid du Colombier 	if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
5769a747e4fSDavid du Colombier 		ou->err = Eronly;
5779a747e4fSDavid du Colombier 		goto out;
5789a747e4fSDavid du Colombier 	}
5799a747e4fSDavid du Colombier 
5809a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
5819a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
5829a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
5839a747e4fSDavid du Colombier 		ou->err = Ealloc;
5849a747e4fSDavid du Colombier 		goto out;
5859a747e4fSDavid du Colombier 	}
5869a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
5879a747e4fSDavid du Colombier 		goto out;
5889a747e4fSDavid du Colombier 	if(!(d->mode & DDIR)) {
5899a747e4fSDavid du Colombier 		ou->err = Edir2;
5909a747e4fSDavid du Colombier 		goto out;
5919a747e4fSDavid du Colombier 	}
5929a747e4fSDavid du Colombier 	if(cp != cons.chan && iaccess(f, d, DWRITE) && !writeallow) {
5939a747e4fSDavid du Colombier 		ou->err = Eaccess;
5949a747e4fSDavid du Colombier 		goto out;
5959a747e4fSDavid du Colombier 	}
5969a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
5979a747e4fSDavid du Colombier 	if(!strncmp(in->name, ".", sizeof(in->name)) ||
5989a747e4fSDavid du Colombier 	   !strncmp(in->name, "..", sizeof(in->name))) {
5999a747e4fSDavid du Colombier 		ou->err = Edot;
6009a747e4fSDavid du Colombier 		goto out;
6019a747e4fSDavid du Colombier 	}
6029a747e4fSDavid du Colombier 	if(checkname(in->name)) {
6039a747e4fSDavid du Colombier 		ou->err = Ename;
6049a747e4fSDavid du Colombier 		goto out;
6059a747e4fSDavid du Colombier 	}
6069a747e4fSDavid du Colombier 	addr1 = 0;
6079a747e4fSDavid du Colombier 	slot1 = 0;	/* set */
6089a747e4fSDavid du Colombier 	for(addr=0;; addr++) {
6099a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0);
6109a747e4fSDavid du Colombier 		if(!p1) {
6119a747e4fSDavid du Colombier 			if(addr1)
6129a747e4fSDavid du Colombier 				break;
6139a747e4fSDavid du Colombier 			p1 = dnodebuf(p, d, addr, Tdir);
6149a747e4fSDavid du Colombier 		}
6159a747e4fSDavid du Colombier 		if(p1 == 0) {
6169a747e4fSDavid du Colombier 			ou->err = Efull;
6179a747e4fSDavid du Colombier 			goto out;
6189a747e4fSDavid du Colombier 		}
6199a747e4fSDavid du Colombier 		if(checktag(p1, Tdir, d->qid.path)) {
6209a747e4fSDavid du Colombier 			putbuf(p1);
6219a747e4fSDavid du Colombier 			goto phase;
6229a747e4fSDavid du Colombier 		}
6239a747e4fSDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
6249a747e4fSDavid du Colombier 			d1 = getdir(p1, slot);
6259a747e4fSDavid du Colombier 			if(!(d1->mode & DALLOC)) {
6269a747e4fSDavid du Colombier 				if(!addr1) {
6279a747e4fSDavid du Colombier 					addr1 = p1->addr;
6289a747e4fSDavid du Colombier 					slot1 = slot + addr*DIRPERBUF;
6299a747e4fSDavid du Colombier 				}
6309a747e4fSDavid du Colombier 				continue;
6319a747e4fSDavid du Colombier 			}
6329a747e4fSDavid du Colombier 			if(!strncmp(in->name, d1->name, sizeof(in->name))) {
6339a747e4fSDavid du Colombier 				putbuf(p1);
6349a747e4fSDavid du Colombier 				ou->err = Eexist;
6359a747e4fSDavid du Colombier 				goto out;
6369a747e4fSDavid du Colombier 			}
6379a747e4fSDavid du Colombier 		}
6389a747e4fSDavid du Colombier 		putbuf(p1);
6399a747e4fSDavid du Colombier 	}
6409a747e4fSDavid du Colombier 	switch(in->mode & 7) {
6419a747e4fSDavid du Colombier 	case MEXEC:
6429a747e4fSDavid du Colombier 	case MREAD:		/* seems only useful to make directories */
6439a747e4fSDavid du Colombier 		fmod = FREAD;
6449a747e4fSDavid du Colombier 		break;
6459a747e4fSDavid du Colombier 
6469a747e4fSDavid du Colombier 	case MWRITE:
6479a747e4fSDavid du Colombier 		fmod = FWRITE;
6489a747e4fSDavid du Colombier 		break;
6499a747e4fSDavid du Colombier 
6509a747e4fSDavid du Colombier 	case MBOTH:
6519a747e4fSDavid du Colombier 		fmod = FREAD+FWRITE;
6529a747e4fSDavid du Colombier 		break;
6539a747e4fSDavid du Colombier 
6549a747e4fSDavid du Colombier 	default:
6559a747e4fSDavid du Colombier 		ou->err = Emode;
6569a747e4fSDavid du Colombier 		goto out;
6579a747e4fSDavid du Colombier 	}
6589a747e4fSDavid du Colombier 	if(in->perm & PDIR)
6599a747e4fSDavid du Colombier 		if((in->mode & MTRUNC) || (in->perm & PAPND) || (fmod & FWRITE))
6609a747e4fSDavid du Colombier 			goto badaccess;
6619a747e4fSDavid du Colombier 	/*
6629a747e4fSDavid du Colombier 	 * do it
6639a747e4fSDavid du Colombier 	 */
6649a747e4fSDavid du Colombier 	path = qidpathgen(&f->fs->dev);
6659a747e4fSDavid du Colombier 	p1 = getbuf(f->fs->dev, addr1, Bread|Bimm|Bmod);
6669a747e4fSDavid du Colombier 	d1 = getdir(p1, slot1);
6679a747e4fSDavid du Colombier 	if(!d1 || checktag(p1, Tdir, d->qid.path)) {
6689a747e4fSDavid du Colombier 		if(p1)
6699a747e4fSDavid du Colombier 			putbuf(p1);
6709a747e4fSDavid du Colombier 		goto phase;
6719a747e4fSDavid du Colombier 	}
6729a747e4fSDavid du Colombier 	if(d1->mode & DALLOC) {
6739a747e4fSDavid du Colombier 		putbuf(p1);
6749a747e4fSDavid du Colombier 		goto phase;
6759a747e4fSDavid du Colombier 	}
6769a747e4fSDavid du Colombier 
6779a747e4fSDavid du Colombier 	strncpy(d1->name, in->name, sizeof(in->name));
6789a747e4fSDavid du Colombier 	/*
6799a747e4fSDavid du Colombier 	 * bogus argument passing -- see console.c
6809a747e4fSDavid du Colombier 	 */
6819a747e4fSDavid du Colombier 	if(cp == cons.chan) {
6829a747e4fSDavid du Colombier 		d1->uid = cons.uid;
6839a747e4fSDavid du Colombier 		d1->gid = cons.gid;
6849a747e4fSDavid du Colombier 	} else {
6859a747e4fSDavid du Colombier 		d1->uid = f->uid;
6869a747e4fSDavid du Colombier 		d1->gid = d->gid;
6879a747e4fSDavid du Colombier 		in->perm &= d->mode | ~0666;
6889a747e4fSDavid du Colombier 		if(in->perm & PDIR)
6899a747e4fSDavid du Colombier 			in->perm &= d->mode | ~0777;
6909a747e4fSDavid du Colombier 	}
6919a747e4fSDavid du Colombier 	d1->qid.path = path;
6929a747e4fSDavid du Colombier 	d1->qid.version = 0;
6939a747e4fSDavid du Colombier 	d1->mode = DALLOC | (in->perm & 0777);
6949a747e4fSDavid du Colombier 	if(in->perm & PDIR) {
6959a747e4fSDavid du Colombier 		d1->mode |= DDIR;
6969a747e4fSDavid du Colombier 		d1->qid.path |= QPDIR;
6979a747e4fSDavid du Colombier 	}
6989a747e4fSDavid du Colombier 	if(in->perm & PAPND)
6999a747e4fSDavid du Colombier 		d1->mode |= DAPND;
7009a747e4fSDavid du Colombier 	t = 0;
7019a747e4fSDavid du Colombier 	if(in->perm & PLOCK) {
7029a747e4fSDavid du Colombier 		d1->mode |= DLOCK;
7039a747e4fSDavid du Colombier 		t = tlocked(p1, d1);
7049a747e4fSDavid du Colombier 	}
7059a747e4fSDavid du Colombier 	accessdir(p1, d1, FWRITE);
7069a747e4fSDavid du Colombier 	mkqid(&qid, d1, 0);
7079a747e4fSDavid du Colombier 	putbuf(p1);
7089a747e4fSDavid du Colombier 	accessdir(p, d, FWRITE);
7099a747e4fSDavid du Colombier 
7109a747e4fSDavid du Colombier 	/*
7119a747e4fSDavid du Colombier 	 * do a walk to new directory entry
7129a747e4fSDavid du Colombier 	 */
7139a747e4fSDavid du Colombier 	w = newwp();
7149a747e4fSDavid du Colombier 	if(!w) {
7159a747e4fSDavid du Colombier 		ou->err = Ewalk;
7169a747e4fSDavid du Colombier 		goto out;
7179a747e4fSDavid du Colombier 	}
7189a747e4fSDavid du Colombier 	w->addr = f->addr;
7199a747e4fSDavid du Colombier 	w->slot = f->slot;
7209a747e4fSDavid du Colombier 	w->up = f->wpath;
7219a747e4fSDavid du Colombier 	f->wpath = w;
7229a747e4fSDavid du Colombier 	f->qid = qid;
7239a747e4fSDavid du Colombier 	f->tlock = t;
7249a747e4fSDavid du Colombier 	f->lastra = 0;
7259a747e4fSDavid du Colombier 	if(in->mode & MRCLOSE)
7269a747e4fSDavid du Colombier 		fmod |= FREMOV;
7279a747e4fSDavid du Colombier 	f->open = fmod;
7289a747e4fSDavid du Colombier 	f->addr = addr1;
7299a747e4fSDavid du Colombier 	f->slot = slot1;
7309a747e4fSDavid du Colombier 	if(t)
7319a747e4fSDavid du Colombier 		t->file = f;
7329a747e4fSDavid du Colombier 	mkqid9p1(&ou->qid, &qid);
7339a747e4fSDavid du Colombier 	goto out;
7349a747e4fSDavid du Colombier 
7359a747e4fSDavid du Colombier badaccess:
7369a747e4fSDavid du Colombier 	ou->err = Eaccess;
7379a747e4fSDavid du Colombier 	goto out;
7389a747e4fSDavid du Colombier 
7399a747e4fSDavid du Colombier phase:
7409a747e4fSDavid du Colombier 	ou->err = Ephase;
7419a747e4fSDavid du Colombier 
7429a747e4fSDavid du Colombier out:
7439a747e4fSDavid du Colombier 	if(p)
7449a747e4fSDavid du Colombier 		putbuf(p);
7459a747e4fSDavid du Colombier 	if(f)
7469a747e4fSDavid du Colombier 		qunlock(f);
7479a747e4fSDavid du Colombier 	ou->fid = in->fid;
7489a747e4fSDavid du Colombier }
7499a747e4fSDavid du Colombier 
7509a747e4fSDavid du Colombier void
f_read(Chan * cp,Oldfcall * in,Oldfcall * ou)7519a747e4fSDavid du Colombier f_read(Chan *cp, Oldfcall *in, Oldfcall *ou)
7529a747e4fSDavid du Colombier {
7539a747e4fSDavid du Colombier 	Iobuf *p, *p1;
7549a747e4fSDavid du Colombier 	File *f;
7559a747e4fSDavid du Colombier 	Dentry *d, *d1;
7569a747e4fSDavid du Colombier 	Tlock *t;
7579a747e4fSDavid du Colombier 	long addr, offset, tim;
7589a747e4fSDavid du Colombier 	int nread, count, n, o, slot;
7599a747e4fSDavid du Colombier 
7609a747e4fSDavid du Colombier 	if(CHAT(cp)) {
7619a747e4fSDavid du Colombier 		print("c_read %d\n", cp->chan);
7629a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
7639a747e4fSDavid du Colombier 		print("	offset = %ld\n", in->offset);
7649a747e4fSDavid du Colombier 		print("	count = %ld\n", in->count);
7659a747e4fSDavid du Colombier 	}
7669a747e4fSDavid du Colombier 
7679a747e4fSDavid du Colombier 	p = 0;
7689a747e4fSDavid du Colombier 	count = in->count;
7699a747e4fSDavid du Colombier 	offset = in->offset;
7709a747e4fSDavid du Colombier 	nread = 0;
7719a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
7729a747e4fSDavid du Colombier 	if(!f) {
7739a747e4fSDavid du Colombier 		ou->err = Efid;
7749a747e4fSDavid du Colombier 		goto out;
7759a747e4fSDavid du Colombier 	}
7769a747e4fSDavid du Colombier 	if(!(f->open & FREAD)) {
7779a747e4fSDavid du Colombier 		ou->err = Eopen;
7789a747e4fSDavid du Colombier 		goto out;
7799a747e4fSDavid du Colombier 	}
7809a747e4fSDavid du Colombier 	if(count < 0 || count > MAXDAT) {
7819a747e4fSDavid du Colombier 		ou->err = Ecount;
7829a747e4fSDavid du Colombier 		goto out;
7839a747e4fSDavid du Colombier 	}
7849a747e4fSDavid du Colombier 	if(offset < 0) {
7859a747e4fSDavid du Colombier 		ou->err = Eoffset;
7869a747e4fSDavid du Colombier 		goto out;
7879a747e4fSDavid du Colombier 	}
7889a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
7899a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
7909a747e4fSDavid du Colombier 	if(!d || !(d->mode & DALLOC)) {
7919a747e4fSDavid du Colombier 		ou->err = Ealloc;
7929a747e4fSDavid du Colombier 		goto out;
7939a747e4fSDavid du Colombier 	}
7949a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
7959a747e4fSDavid du Colombier 		goto out;
7969a747e4fSDavid du Colombier 	if(t = f->tlock) {
7979a747e4fSDavid du Colombier 		tim = time(0);
7989a747e4fSDavid du Colombier 		if(t->time < tim || t->file != f) {
7999a747e4fSDavid du Colombier 			ou->err = Ebroken;
8009a747e4fSDavid du Colombier 			goto out;
8019a747e4fSDavid du Colombier 		}
8029a747e4fSDavid du Colombier 		/* renew the lock */
8039a747e4fSDavid du Colombier 		t->time = tim + TLOCK;
8049a747e4fSDavid du Colombier 	}
8059a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
8069a747e4fSDavid du Colombier 	if(d->mode & DDIR) {
8079a747e4fSDavid du Colombier 		addr = 0;
8089a747e4fSDavid du Colombier 		goto dread;
8099a747e4fSDavid du Colombier 	}
8109a747e4fSDavid du Colombier 	if(offset+count > d->size)
8119a747e4fSDavid du Colombier 		count = d->size - offset;
8129a747e4fSDavid du Colombier 	while(count > 0) {
8139a747e4fSDavid du Colombier 		addr = offset / BUFSIZE;
8149a747e4fSDavid du Colombier 		if(addr == f->lastra+1)
8159a747e4fSDavid du Colombier 			dbufread(p, d, addr+1);
8169a747e4fSDavid du Colombier 		f->lastra = addr;
8179a747e4fSDavid du Colombier 		o = offset % BUFSIZE;
8189a747e4fSDavid du Colombier 		n = BUFSIZE - o;
8199a747e4fSDavid du Colombier 		if(n > count)
8209a747e4fSDavid du Colombier 			n = count;
8219a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0);
8229a747e4fSDavid du Colombier 		if(p1) {
8239a747e4fSDavid du Colombier 			if(checktag(p1, Tfile, QPNONE)) {
8249a747e4fSDavid du Colombier 				ou->err = Ephase;
8259a747e4fSDavid du Colombier 				putbuf(p1);
8269a747e4fSDavid du Colombier 				goto out;
8279a747e4fSDavid du Colombier 			}
8289a747e4fSDavid du Colombier 			memmove(ou->data+nread, p1->iobuf+o, n);
8299a747e4fSDavid du Colombier 			putbuf(p1);
8309a747e4fSDavid du Colombier 		} else
8319a747e4fSDavid du Colombier 			memset(ou->data+nread, 0, n);
8329a747e4fSDavid du Colombier 		count -= n;
8339a747e4fSDavid du Colombier 		nread += n;
8349a747e4fSDavid du Colombier 		offset += n;
8359a747e4fSDavid du Colombier 	}
8369a747e4fSDavid du Colombier 	goto out;
8379a747e4fSDavid du Colombier 
8389a747e4fSDavid du Colombier dread:
8399a747e4fSDavid du Colombier 	p1 = dnodebuf(p, d, addr, 0);
8409a747e4fSDavid du Colombier 	if(!p1)
8419a747e4fSDavid du Colombier 		goto out;
8429a747e4fSDavid du Colombier 	if(checktag(p1, Tdir, QPNONE)) {
8439a747e4fSDavid du Colombier 		ou->err = Ephase;
8449a747e4fSDavid du Colombier 		putbuf(p1);
8459a747e4fSDavid du Colombier 		goto out;
8469a747e4fSDavid du Colombier 	}
8479a747e4fSDavid du Colombier 	n = DIRREC;
8489a747e4fSDavid du Colombier 	for(slot=0; slot<DIRPERBUF; slot++) {
8499a747e4fSDavid du Colombier 		d1 = getdir(p1, slot);
8509a747e4fSDavid du Colombier 		if(!(d1->mode & DALLOC))
8519a747e4fSDavid du Colombier 			continue;
8529a747e4fSDavid du Colombier 		if(offset >= n) {
8539a747e4fSDavid du Colombier 			offset -= n;
8549a747e4fSDavid du Colombier 			continue;
8559a747e4fSDavid du Colombier 		}
8569a747e4fSDavid du Colombier 		if(count < n) {
8579a747e4fSDavid du Colombier 			putbuf(p1);
8589a747e4fSDavid du Colombier 			goto out;
8599a747e4fSDavid du Colombier 		}
8609a747e4fSDavid du Colombier 		if(convD2M9p1(d1, ou->data+nread) != n)
8619a747e4fSDavid du Colombier 			print("dirread convD2M\n");
8629a747e4fSDavid du Colombier 		nread += n;
8639a747e4fSDavid du Colombier 		count -= n;
8649a747e4fSDavid du Colombier 	}
8659a747e4fSDavid du Colombier 	putbuf(p1);
8669a747e4fSDavid du Colombier 	addr++;
8679a747e4fSDavid du Colombier 	goto dread;
8689a747e4fSDavid du Colombier 
8699a747e4fSDavid du Colombier out:
8709a747e4fSDavid du Colombier 	count = in->count - nread;
8719a747e4fSDavid du Colombier 	if(count > 0)
8729a747e4fSDavid du Colombier 		memset(ou->data+nread, 0, count);
8739a747e4fSDavid du Colombier 	if(p)
8749a747e4fSDavid du Colombier 		putbuf(p);
8759a747e4fSDavid du Colombier 	if(f)
8769a747e4fSDavid du Colombier 		qunlock(f);
8779a747e4fSDavid du Colombier 	ou->fid = in->fid;
8789a747e4fSDavid du Colombier 	ou->count = nread;
8799a747e4fSDavid du Colombier 	if(CHAT(cp))
8809a747e4fSDavid du Colombier 		print("	nread = %d\n", nread);
8819a747e4fSDavid du Colombier }
8829a747e4fSDavid du Colombier 
8839a747e4fSDavid du Colombier void
f_write(Chan * cp,Oldfcall * in,Oldfcall * ou)8849a747e4fSDavid du Colombier f_write(Chan *cp, Oldfcall *in, Oldfcall *ou)
8859a747e4fSDavid du Colombier {
8869a747e4fSDavid du Colombier 	Iobuf *p, *p1;
8879a747e4fSDavid du Colombier 	Dentry *d;
8889a747e4fSDavid du Colombier 	File *f;
8899a747e4fSDavid du Colombier 	Tlock *t;
8909a747e4fSDavid du Colombier 	long offset, addr, tim;
8919a747e4fSDavid du Colombier 	int count, nwrite, o, n;
8929a747e4fSDavid du Colombier 
8939a747e4fSDavid du Colombier 	if(CHAT(cp)) {
8949a747e4fSDavid du Colombier 		print("c_write %d\n", cp->chan);
8959a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
8969a747e4fSDavid du Colombier 		print("	offset = %ld\n", in->offset);
8979a747e4fSDavid du Colombier 		print("	count = %ld\n", in->count);
8989a747e4fSDavid du Colombier 	}
8999a747e4fSDavid du Colombier 
9009a747e4fSDavid du Colombier 	offset = in->offset;
9019a747e4fSDavid du Colombier 	count = in->count;
9029a747e4fSDavid du Colombier 	nwrite = 0;
9039a747e4fSDavid du Colombier 	p = 0;
9049a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
9059a747e4fSDavid du Colombier 	if(!f) {
9069a747e4fSDavid du Colombier 		ou->err = Efid;
9079a747e4fSDavid du Colombier 		goto out;
9089a747e4fSDavid du Colombier 	}
9099a747e4fSDavid du Colombier 	if(!(f->open & FWRITE)) {
9109a747e4fSDavid du Colombier 		ou->err = Eopen;
9119a747e4fSDavid du Colombier 		goto out;
9129a747e4fSDavid du Colombier 	}
9135d459b5aSDavid du Colombier 	if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
9149a747e4fSDavid du Colombier 		ou->err = Eronly;
9159a747e4fSDavid du Colombier 		goto out;
9169a747e4fSDavid du Colombier 	}
9179a747e4fSDavid du Colombier 	if(count < 0 || count > MAXDAT) {
9189a747e4fSDavid du Colombier 		ou->err = Ecount;
9199a747e4fSDavid du Colombier 		goto out;
9209a747e4fSDavid du Colombier 	}
9219a747e4fSDavid du Colombier 	if(offset < 0) {
9229a747e4fSDavid du Colombier 		ou->err = Eoffset;
9239a747e4fSDavid du Colombier 		goto out;
9249a747e4fSDavid du Colombier 	}
9259a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread|Bmod);
9269a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
9279a747e4fSDavid du Colombier 	if(!d || !(d->mode & DALLOC)) {
9289a747e4fSDavid du Colombier 		ou->err = Ealloc;
9299a747e4fSDavid du Colombier 		goto out;
9309a747e4fSDavid du Colombier 	}
9319a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
9329a747e4fSDavid du Colombier 		goto out;
9339a747e4fSDavid du Colombier 	if(t = f->tlock) {
9349a747e4fSDavid du Colombier 		tim = time(0);
9359a747e4fSDavid du Colombier 		if(t->time < tim || t->file != f) {
9369a747e4fSDavid du Colombier 			ou->err = Ebroken;
9379a747e4fSDavid du Colombier 			goto out;
9389a747e4fSDavid du Colombier 		}
9399a747e4fSDavid du Colombier 		/* renew the lock */
9409a747e4fSDavid du Colombier 		t->time = tim + TLOCK;
9419a747e4fSDavid du Colombier 	}
9429a747e4fSDavid du Colombier 	accessdir(p, d, FWRITE);
9439a747e4fSDavid du Colombier 	if(d->mode & DAPND)
9449a747e4fSDavid du Colombier 		offset = d->size;
9459a747e4fSDavid du Colombier 	if(offset+count > d->size)
9469a747e4fSDavid du Colombier 		d->size = offset+count;
9479a747e4fSDavid du Colombier 	while(count > 0) {
9489a747e4fSDavid du Colombier 		addr = offset / BUFSIZE;
9499a747e4fSDavid du Colombier 		o = offset % BUFSIZE;
9509a747e4fSDavid du Colombier 		n = BUFSIZE - o;
9519a747e4fSDavid du Colombier 		if(n > count)
9529a747e4fSDavid du Colombier 			n = count;
9539a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, Tfile);
9549a747e4fSDavid du Colombier 		if(p1 == 0) {
9559a747e4fSDavid du Colombier 			ou->err = Efull;
9569a747e4fSDavid du Colombier 			goto out;
9579a747e4fSDavid du Colombier 		}
9589a747e4fSDavid du Colombier 		if(checktag(p1, Tfile, d->qid.path)) {
9599a747e4fSDavid du Colombier 			putbuf(p1);
9609a747e4fSDavid du Colombier 			ou->err = Ephase;
9619a747e4fSDavid du Colombier 			goto out;
9629a747e4fSDavid du Colombier 		}
9639a747e4fSDavid du Colombier 		memmove(p1->iobuf+o, in->data+nwrite, n);
9649a747e4fSDavid du Colombier 		p1->flags |= Bmod;
9659a747e4fSDavid du Colombier 		putbuf(p1);
9669a747e4fSDavid du Colombier 		count -= n;
9679a747e4fSDavid du Colombier 		nwrite += n;
9689a747e4fSDavid du Colombier 		offset += n;
9699a747e4fSDavid du Colombier 	}
9709a747e4fSDavid du Colombier 	if(CHAT(cp))
9719a747e4fSDavid du Colombier 		print("	nwrite = %d\n", nwrite);
9729a747e4fSDavid du Colombier 
9739a747e4fSDavid du Colombier out:
9749a747e4fSDavid du Colombier 	if(p)
9759a747e4fSDavid du Colombier 		putbuf(p);
9769a747e4fSDavid du Colombier 	if(f)
9779a747e4fSDavid du Colombier 		qunlock(f);
9789a747e4fSDavid du Colombier 	ou->fid = in->fid;
9799a747e4fSDavid du Colombier 	ou->count = nwrite;
9809a747e4fSDavid du Colombier }
9819a747e4fSDavid du Colombier 
9829a747e4fSDavid du Colombier int
doremove(File * f,int iscon)9839a747e4fSDavid du Colombier doremove(File *f, int iscon)
9849a747e4fSDavid du Colombier {
9859a747e4fSDavid du Colombier 	Iobuf *p, *p1;
9869a747e4fSDavid du Colombier 	Dentry *d, *d1;
9879a747e4fSDavid du Colombier 	long addr;
9889a747e4fSDavid du Colombier 	int slot, err;
9899a747e4fSDavid du Colombier 
9909a747e4fSDavid du Colombier 	p = 0;
9919a747e4fSDavid du Colombier 	p1 = 0;
9925d459b5aSDavid du Colombier 	if(isro(f->fs->dev) || (f->cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
9939a747e4fSDavid du Colombier 		err = Eronly;
9949a747e4fSDavid du Colombier 		goto out;
9959a747e4fSDavid du Colombier 	}
9969a747e4fSDavid du Colombier 	/*
9979a747e4fSDavid du Colombier 	 * check on parent directory of file to be deleted
9989a747e4fSDavid du Colombier 	 */
9999a747e4fSDavid du Colombier 	if(f->wpath == 0 || f->wpath->addr == f->addr) {
10009a747e4fSDavid du Colombier 		err = Ephase;
10019a747e4fSDavid du Colombier 		goto out;
10029a747e4fSDavid du Colombier 	}
10039a747e4fSDavid du Colombier 	p1 = getbuf(f->fs->dev, f->wpath->addr, Bread);
10049a747e4fSDavid du Colombier 	d1 = getdir(p1, f->wpath->slot);
10059a747e4fSDavid du Colombier 	if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
10069a747e4fSDavid du Colombier 		err = Ephase;
10079a747e4fSDavid du Colombier 		goto out;
10089a747e4fSDavid du Colombier 	}
10099a747e4fSDavid du Colombier 	if(!iscon && iaccess(f, d1, DWRITE)) {
10109a747e4fSDavid du Colombier 		err = Eaccess;
10119a747e4fSDavid du Colombier 		goto out;
10129a747e4fSDavid du Colombier 	}
10139a747e4fSDavid du Colombier 	accessdir(p1, d1, FWRITE);
10149a747e4fSDavid du Colombier 	putbuf(p1);
10159a747e4fSDavid du Colombier 	p1 = 0;
10169a747e4fSDavid du Colombier 
10179a747e4fSDavid du Colombier 	/*
10189a747e4fSDavid du Colombier 	 * check on file to be deleted
10199a747e4fSDavid du Colombier 	 */
10209a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
10219a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
10229a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
10239a747e4fSDavid du Colombier 		err = Ealloc;
10249a747e4fSDavid du Colombier 		goto out;
10259a747e4fSDavid du Colombier 	}
10269a747e4fSDavid du Colombier 	if(err = mkqidcmp(&f->qid, d))
10279a747e4fSDavid du Colombier 		goto out;
10289a747e4fSDavid du Colombier 
10299a747e4fSDavid du Colombier 	/*
10309a747e4fSDavid du Colombier 	 * if deleting a directory, make sure it is empty
10319a747e4fSDavid du Colombier 	 */
10329a747e4fSDavid du Colombier 	if((d->mode & DDIR))
10339a747e4fSDavid du Colombier 	for(addr=0;; addr++) {
10349a747e4fSDavid du Colombier 		p1 = dnodebuf(p, d, addr, 0);
10359a747e4fSDavid du Colombier 		if(!p1)
10369a747e4fSDavid du Colombier 			break;
10379a747e4fSDavid du Colombier 		if(checktag(p1, Tdir, d->qid.path)) {
10389a747e4fSDavid du Colombier 			err = Ephase;
10399a747e4fSDavid du Colombier 			goto out;
10409a747e4fSDavid du Colombier 		}
10419a747e4fSDavid du Colombier 		for(slot=0; slot<DIRPERBUF; slot++) {
10429a747e4fSDavid du Colombier 			d1 = getdir(p1, slot);
10439a747e4fSDavid du Colombier 			if(!(d1->mode & DALLOC))
10449a747e4fSDavid du Colombier 				continue;
10459a747e4fSDavid du Colombier 			err = Eempty;
10469a747e4fSDavid du Colombier 			goto out;
10479a747e4fSDavid du Colombier 		}
10489a747e4fSDavid du Colombier 		putbuf(p1);
10499a747e4fSDavid du Colombier 	}
10509a747e4fSDavid du Colombier 
10519a747e4fSDavid du Colombier 	/*
10529a747e4fSDavid du Colombier 	 * do it
10539a747e4fSDavid du Colombier 	 */
10549a747e4fSDavid du Colombier 	dtrunc(p, d);
10559a747e4fSDavid du Colombier 	memset(d, 0, sizeof(Dentry));
10569a747e4fSDavid du Colombier 	settag(p, Tdir, QPNONE);
10579a747e4fSDavid du Colombier 
10589a747e4fSDavid du Colombier out:
10599a747e4fSDavid du Colombier 	if(p1)
10609a747e4fSDavid du Colombier 		putbuf(p1);
10619a747e4fSDavid du Colombier 	if(p)
10629a747e4fSDavid du Colombier 		putbuf(p);
10639a747e4fSDavid du Colombier 	return err;
10649a747e4fSDavid du Colombier }
10659a747e4fSDavid du Colombier 
10669a747e4fSDavid du Colombier void
f_remove(Chan * cp,Oldfcall * in,Oldfcall * ou)10679a747e4fSDavid du Colombier f_remove(Chan *cp, Oldfcall *in, Oldfcall *ou)
10689a747e4fSDavid du Colombier {
10699a747e4fSDavid du Colombier 	File *f;
10709a747e4fSDavid du Colombier 
10719a747e4fSDavid du Colombier 	if(CHAT(cp)) {
10729a747e4fSDavid du Colombier 		print("c_remove %d\n", cp->chan);
10739a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
10749a747e4fSDavid du Colombier 	}
10759a747e4fSDavid du Colombier 
10769a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
10779a747e4fSDavid du Colombier 	if(!f) {
10789a747e4fSDavid du Colombier 		ou->err = Efid;
10799a747e4fSDavid du Colombier 		goto out;
10809a747e4fSDavid du Colombier 	}
10819a747e4fSDavid du Colombier 	ou->err = doremove(f, cp==cons.chan);
10829a747e4fSDavid du Colombier 
10839a747e4fSDavid du Colombier out:
10849a747e4fSDavid du Colombier 	ou->fid = in->fid;
10859a747e4fSDavid du Colombier 	if(f)
10869a747e4fSDavid du Colombier 		qunlock(f);
10879a747e4fSDavid du Colombier }
10889a747e4fSDavid du Colombier 
10899a747e4fSDavid du Colombier void
f_stat(Chan * cp,Oldfcall * in,Oldfcall * ou)10909a747e4fSDavid du Colombier f_stat(Chan *cp, Oldfcall *in, Oldfcall *ou)
10919a747e4fSDavid du Colombier {
10929a747e4fSDavid du Colombier 	Iobuf *p;
10939a747e4fSDavid du Colombier 	Dentry *d;
10949a747e4fSDavid du Colombier 	File *f;
10959a747e4fSDavid du Colombier 
10969a747e4fSDavid du Colombier 	if(CHAT(cp)) {
10979a747e4fSDavid du Colombier 		print("c_stat %d\n", cp->chan);
10989a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
10999a747e4fSDavid du Colombier 	}
11009a747e4fSDavid du Colombier 
11019a747e4fSDavid du Colombier 	p = 0;
11029a747e4fSDavid du Colombier 	memset(ou->stat, 0, sizeof(ou->stat));
11039a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
11049a747e4fSDavid du Colombier 	if(!f) {
11059a747e4fSDavid du Colombier 		ou->err = Efid;
11069a747e4fSDavid du Colombier 		goto out;
11079a747e4fSDavid du Colombier 	}
11089a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
11099a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
11109a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
11119a747e4fSDavid du Colombier 		ou->err = Ealloc;
11129a747e4fSDavid du Colombier 		goto out;
11139a747e4fSDavid du Colombier 	}
11149a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
11159a747e4fSDavid du Colombier 		goto out;
11169a747e4fSDavid du Colombier 	if(d->qid.path == QPROOT)	/* stat of root gives time */
11179a747e4fSDavid du Colombier 		d->atime = time(0);
11189a747e4fSDavid du Colombier 	if(convD2M9p1(d, ou->stat) != DIRREC)
11199a747e4fSDavid du Colombier 		print("stat convD2M\n");
11209a747e4fSDavid du Colombier 
11219a747e4fSDavid du Colombier out:
11229a747e4fSDavid du Colombier 	if(p)
11239a747e4fSDavid du Colombier 		putbuf(p);
11249a747e4fSDavid du Colombier 	if(f)
11259a747e4fSDavid du Colombier 		qunlock(f);
11269a747e4fSDavid du Colombier 	ou->fid = in->fid;
11279a747e4fSDavid du Colombier }
11289a747e4fSDavid du Colombier 
11299a747e4fSDavid du Colombier void
f_wstat(Chan * cp,Oldfcall * in,Oldfcall * ou)11309a747e4fSDavid du Colombier f_wstat(Chan *cp, Oldfcall *in, Oldfcall *ou)
11319a747e4fSDavid du Colombier {
11329a747e4fSDavid du Colombier 	Iobuf *p, *p1;
11339a747e4fSDavid du Colombier 	Dentry *d, *d1, xd;
11349a747e4fSDavid du Colombier 	File *f;
11359a747e4fSDavid du Colombier 	int slot;
11369a747e4fSDavid du Colombier 	long addr;
11379a747e4fSDavid du Colombier 
11389a747e4fSDavid du Colombier 	if(CHAT(cp)) {
11399a747e4fSDavid du Colombier 		print("c_wstat %d\n", cp->chan);
11409a747e4fSDavid du Colombier 		print("	fid = %d\n", in->fid);
11419a747e4fSDavid du Colombier 	}
11429a747e4fSDavid du Colombier 
11439a747e4fSDavid du Colombier 	p = 0;
11449a747e4fSDavid du Colombier 	p1 = 0;
11459a747e4fSDavid du Colombier 	d1 = 0;
11469a747e4fSDavid du Colombier 	f = filep(cp, in->fid, 0);
11479a747e4fSDavid du Colombier 	if(!f) {
11489a747e4fSDavid du Colombier 		ou->err = Efid;
11499a747e4fSDavid du Colombier 		goto out;
11509a747e4fSDavid du Colombier 	}
11515d459b5aSDavid du Colombier 	if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
11529a747e4fSDavid du Colombier 		ou->err = Eronly;
11539a747e4fSDavid du Colombier 		goto out;
11549a747e4fSDavid du Colombier 	}
11559a747e4fSDavid du Colombier 
11569a747e4fSDavid du Colombier 	/*
11579a747e4fSDavid du Colombier 	 * first get parent
11589a747e4fSDavid du Colombier 	 */
11599a747e4fSDavid du Colombier 	if(f->wpath) {
11609a747e4fSDavid du Colombier 		p1 = getbuf(f->fs->dev, f->wpath->addr, Bread);
11619a747e4fSDavid du Colombier 		d1 = getdir(p1, f->wpath->slot);
11629a747e4fSDavid du Colombier 		if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
11639a747e4fSDavid du Colombier 			ou->err = Ephase;
11649a747e4fSDavid du Colombier 			goto out;
11659a747e4fSDavid du Colombier 		}
11669a747e4fSDavid du Colombier 	}
11679a747e4fSDavid du Colombier 
11689a747e4fSDavid du Colombier 	p = getbuf(f->fs->dev, f->addr, Bread);
11699a747e4fSDavid du Colombier 	d = getdir(p, f->slot);
11709a747e4fSDavid du Colombier 	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
11719a747e4fSDavid du Colombier 		ou->err = Ealloc;
11729a747e4fSDavid du Colombier 		goto out;
11739a747e4fSDavid du Colombier 	}
11749a747e4fSDavid du Colombier 	if(ou->err = mkqidcmp(&f->qid, d))
11759a747e4fSDavid du Colombier 		goto out;
11769a747e4fSDavid du Colombier 
11779a747e4fSDavid du Colombier 	convM2D9p1(in->stat, &xd);
11789a747e4fSDavid du Colombier 	if(CHAT(cp)) {
11799a747e4fSDavid du Colombier 		print("	d.name = %s\n", xd.name);
11809a747e4fSDavid du Colombier 		print("	d.uid  = %d\n", xd.uid);
11819a747e4fSDavid du Colombier 		print("	d.gid  = %d\n", xd.gid);
11829a747e4fSDavid du Colombier 		print("	d.mode = %.4x\n", xd.mode);
11839a747e4fSDavid du Colombier 	}
11849a747e4fSDavid du Colombier 
11859a747e4fSDavid du Colombier 	/*
11869a747e4fSDavid du Colombier 	 * if chown,
11879a747e4fSDavid du Colombier 	 * must be god
11889a747e4fSDavid du Colombier 	 */
11899a747e4fSDavid du Colombier 	while(xd.uid != d->uid) {
11909a747e4fSDavid du Colombier 		if(wstatallow)			/* set to allow chown during boot */
11919a747e4fSDavid du Colombier 			break;
11929a747e4fSDavid du Colombier 		ou->err = Enotu;
11939a747e4fSDavid du Colombier 		goto out;
11949a747e4fSDavid du Colombier 	}
11959a747e4fSDavid du Colombier 
11969a747e4fSDavid du Colombier 	/*
11979a747e4fSDavid du Colombier 	 * if chgroup,
11989a747e4fSDavid du Colombier 	 * must be either
11999a747e4fSDavid du Colombier 	 *	a) owner and in new group
12009a747e4fSDavid du Colombier 	 *	b) leader of both groups
12019a747e4fSDavid du Colombier 	 */
12029a747e4fSDavid du Colombier 	while(xd.gid != d->gid) {
12039a747e4fSDavid du Colombier 		if(wstatallow || writeallow)		/* set to allow chgrp during boot */
12049a747e4fSDavid du Colombier 			break;
12059a747e4fSDavid du Colombier 		if(d->uid == f->uid && ingroup(f->uid, xd.gid))
12069a747e4fSDavid du Colombier 			break;
12079a747e4fSDavid du Colombier 		if(leadgroup(f->uid, xd.gid))
12089a747e4fSDavid du Colombier 			if(leadgroup(f->uid, d->gid))
12099a747e4fSDavid du Colombier 				break;
12109a747e4fSDavid du Colombier 		ou->err = Enotg;
12119a747e4fSDavid du Colombier 		goto out;
12129a747e4fSDavid du Colombier 	}
12139a747e4fSDavid du Colombier 
12149a747e4fSDavid du Colombier 	/*
12159a747e4fSDavid du Colombier 	 * if rename,
12169a747e4fSDavid du Colombier 	 * must have write permission in parent
12179a747e4fSDavid du Colombier 	 */
12189a747e4fSDavid du Colombier 	if(xd.name[0] == 0)
12199a747e4fSDavid du Colombier 		strncpy(xd.name, d->name, sizeof(xd.name));
12209a747e4fSDavid du Colombier 	while(strncmp(d->name, xd.name, sizeof(d->name)) != 0) {
12219a747e4fSDavid du Colombier 		if(checkname(xd.name)) {
12229a747e4fSDavid du Colombier 			ou->err = Ename;
12239a747e4fSDavid du Colombier 			goto out;
12249a747e4fSDavid du Colombier 		}
12259a747e4fSDavid du Colombier 
12269a747e4fSDavid du Colombier 		if(strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
12279a747e4fSDavid du Colombier 			ou->err = Ename;
12289a747e4fSDavid du Colombier 			goto out;
12299a747e4fSDavid du Colombier 		}
12309a747e4fSDavid du Colombier 
12319a747e4fSDavid du Colombier 		/*
12329a747e4fSDavid du Colombier 		 * drop entry to prevent lock, then
12339a747e4fSDavid du Colombier 		 * check that destination name is unique,
12349a747e4fSDavid du Colombier 		 */
12359a747e4fSDavid du Colombier 		putbuf(p);
12369a747e4fSDavid du Colombier 		for(addr=0;; addr++) {
12379a747e4fSDavid du Colombier 			p = dnodebuf(p1, d1, addr, 0);
12389a747e4fSDavid du Colombier 			if(!p)
12399a747e4fSDavid du Colombier 				break;
12409a747e4fSDavid du Colombier 			if(checktag(p, Tdir, d1->qid.path)) {
12419a747e4fSDavid du Colombier 				putbuf(p);
12429a747e4fSDavid du Colombier 				continue;
12439a747e4fSDavid du Colombier 			}
12449a747e4fSDavid du Colombier 			for(slot=0; slot<DIRPERBUF; slot++) {
12459a747e4fSDavid du Colombier 				d = getdir(p, slot);
12469a747e4fSDavid du Colombier 				if(!(d->mode & DALLOC))
12479a747e4fSDavid du Colombier 					continue;
12489a747e4fSDavid du Colombier 				if(!strncmp(xd.name, d->name, sizeof(xd.name))) {
12499a747e4fSDavid du Colombier 					ou->err = Eexist;
12509a747e4fSDavid du Colombier 					goto out;
12519a747e4fSDavid du Colombier 				}
12529a747e4fSDavid du Colombier 			}
12539a747e4fSDavid du Colombier 			putbuf(p);
12549a747e4fSDavid du Colombier 		}
12559a747e4fSDavid du Colombier 
12569a747e4fSDavid du Colombier 		/*
12579a747e4fSDavid du Colombier 		 * reacquire entry
12589a747e4fSDavid du Colombier 		 */
12599a747e4fSDavid du Colombier 		p = getbuf(f->fs->dev, f->addr, Bread);
12609a747e4fSDavid du Colombier 		d = getdir(p, f->slot);
12619a747e4fSDavid du Colombier 		if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
12629a747e4fSDavid du Colombier 			ou->err = Ephase;
12639a747e4fSDavid du Colombier 			goto out;
12649a747e4fSDavid du Colombier 		}
12659a747e4fSDavid du Colombier 
12669a747e4fSDavid du Colombier 		if(wstatallow || writeallow) /* set to allow rename during boot */
12679a747e4fSDavid du Colombier 			break;
12689a747e4fSDavid du Colombier 		if(!d1 || iaccess(f, d1, DWRITE)) {
12699a747e4fSDavid du Colombier 			ou->err = Eaccess;
12709a747e4fSDavid du Colombier 			goto out;
12719a747e4fSDavid du Colombier 		}
12729a747e4fSDavid du Colombier 		break;
12739a747e4fSDavid du Colombier 	}
12749a747e4fSDavid du Colombier 
12759a747e4fSDavid du Colombier 	/*
12769a747e4fSDavid du Colombier 	 * if mode/time, either
12779a747e4fSDavid du Colombier 	 *	a) owner
12789a747e4fSDavid du Colombier 	 *	b) leader of either group
12799a747e4fSDavid du Colombier 	 */
12809a747e4fSDavid du Colombier 	while(d->mtime != xd.mtime ||
12819a747e4fSDavid du Colombier 	     ((d->mode^xd.mode) & (DAPND|DLOCK|0777))) {
12829a747e4fSDavid du Colombier 		if(wstatallow)			/* set to allow chmod during boot */
12839a747e4fSDavid du Colombier 			break;
12849a747e4fSDavid du Colombier 		if(d->uid == f->uid)
12859a747e4fSDavid du Colombier 			break;
12869a747e4fSDavid du Colombier 		if(leadgroup(f->uid, xd.gid))
12879a747e4fSDavid du Colombier 			break;
12889a747e4fSDavid du Colombier 		if(leadgroup(f->uid, d->gid))
12899a747e4fSDavid du Colombier 			break;
12909a747e4fSDavid du Colombier 		ou->err = Enotu;
12919a747e4fSDavid du Colombier 		goto out;
12929a747e4fSDavid du Colombier 	}
12939a747e4fSDavid du Colombier 	d->mtime = xd.mtime;
12949a747e4fSDavid du Colombier 	d->uid = xd.uid;
12959a747e4fSDavid du Colombier 	d->gid = xd.gid;
12969a747e4fSDavid du Colombier 	d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
12979a747e4fSDavid du Colombier 
12989a747e4fSDavid du Colombier 	strncpy(d->name, xd.name, sizeof(d->name));
12999a747e4fSDavid du Colombier 	if(wstatallow) {
13009a747e4fSDavid du Colombier 		p->flags |= Bmod;
13019a747e4fSDavid du Colombier 		if(xd.atime)
13029a747e4fSDavid du Colombier 			d->atime = xd.atime;
13039a747e4fSDavid du Colombier 		if(xd.mtime)
13049a747e4fSDavid du Colombier 			d->mtime = xd.mtime;
13059a747e4fSDavid du Colombier 	} else
1306*229d2d34SDavid du Colombier 		accessdir(p, d, FWSTAT);
13079a747e4fSDavid du Colombier 
13089a747e4fSDavid du Colombier out:
13099a747e4fSDavid du Colombier 	if(p)
13109a747e4fSDavid du Colombier 		putbuf(p);
13119a747e4fSDavid du Colombier 	if(p1)
13129a747e4fSDavid du Colombier 		putbuf(p1);
13139a747e4fSDavid du Colombier 	if(f)
13149a747e4fSDavid du Colombier 		qunlock(f);
13159a747e4fSDavid du Colombier 	ou->fid = in->fid;
13169a747e4fSDavid du Colombier }
13179a747e4fSDavid du Colombier 
13189a747e4fSDavid du Colombier void
13199a747e4fSDavid du Colombier (*call9p1[MAXSYSCALL])(Chan*, Oldfcall*, Oldfcall*) =
13209a747e4fSDavid du Colombier {
13219a747e4fSDavid du Colombier 	[Tnop9p1]		f_nop,
13229a747e4fSDavid du Colombier 	[Tosession9p1]	f_session,
13239a747e4fSDavid du Colombier 	[Tsession9p1]	f_session,
13249a747e4fSDavid du Colombier 	[Tflush9p1]	f_flush,
13259a747e4fSDavid du Colombier 	[Toattach9p1]	f_attach,
13269a747e4fSDavid du Colombier 	[Tattach9p1]	f_attach,
13279a747e4fSDavid du Colombier 	[Tclone9p1]	f_clone,
13289a747e4fSDavid du Colombier 	[Twalk9p1]		f_walk,
13299a747e4fSDavid du Colombier 	[Topen9p1]		f_open,
13309a747e4fSDavid du Colombier 	[Tcreate9p1]	f_create,
13319a747e4fSDavid du Colombier 	[Tread9p1]		f_read,
13329a747e4fSDavid du Colombier 	[Twrite9p1]	f_write,
13339a747e4fSDavid du Colombier 	[Tclunk9p1]	f_clunk,
13349a747e4fSDavid du Colombier 	[Tremove9p1]	f_remove,
13359a747e4fSDavid du Colombier 	[Tstat9p1]		f_stat,
13369a747e4fSDavid du Colombier 	[Twstat9p1]	f_wstat,
13379a747e4fSDavid du Colombier 	[Tclwalk9p1]	f_clwalk,
13389a747e4fSDavid du Colombier };
13399a747e4fSDavid du Colombier 
13409a747e4fSDavid du Colombier static void
send(Chan * c,uchar * buf,int n)13419a747e4fSDavid du Colombier send(Chan *c, uchar *buf, int n)
13429a747e4fSDavid du Colombier {
13439a747e4fSDavid du Colombier 	int fd, m;
13449a747e4fSDavid du Colombier 
13459a747e4fSDavid du Colombier 	fd = c->chan;
13469a747e4fSDavid du Colombier 	m = write(fd, buf, n);
13479a747e4fSDavid du Colombier 	if(m == n)
13489a747e4fSDavid du Colombier 		return;
13499a747e4fSDavid du Colombier 	panic("write failed");
13509a747e4fSDavid du Colombier }
13519a747e4fSDavid du Colombier 
13529a747e4fSDavid du Colombier void
error9p1(Chan * c,uchar * buf)13539a747e4fSDavid du Colombier error9p1(Chan *c, uchar *buf)
13549a747e4fSDavid du Colombier {
13559a747e4fSDavid du Colombier 	buf[0] = Rnop9p1;
13569a747e4fSDavid du Colombier 	buf[1] = ~0;
13579a747e4fSDavid du Colombier 	buf[2] = ~0;
13589a747e4fSDavid du Colombier 
13599a747e4fSDavid du Colombier 	send(c, buf, 3);
13609a747e4fSDavid du Colombier }
13619a747e4fSDavid du Colombier 
13629a747e4fSDavid du Colombier void
serve9p1(Chan * chan,uchar * ib,int nib)13639a747e4fSDavid du Colombier serve9p1(Chan *chan, uchar *ib, int nib)
13649a747e4fSDavid du Colombier {
13659a747e4fSDavid du Colombier 	int n, t;
13669a747e4fSDavid du Colombier 	uchar inbuf[MAXMSG+MAXDAT], outbuf[MAXMSG+MAXDAT];
13679a747e4fSDavid du Colombier 	Oldfcall fi, fo;
13689a747e4fSDavid du Colombier 
13699a747e4fSDavid du Colombier 	for(;;){
13709a747e4fSDavid du Colombier 		if(nib){
13719a747e4fSDavid du Colombier 			memmove(inbuf, ib, nib);
13729a747e4fSDavid du Colombier 			n = nib;
13739a747e4fSDavid du Colombier 			nib = 0;
13749a747e4fSDavid du Colombier 		}else
13759a747e4fSDavid du Colombier 			n = read(chan->chan, inbuf, sizeof inbuf);
13769a747e4fSDavid du Colombier 		if(chat)
13779a747e4fSDavid du Colombier 			print("read msg %d\n", n);
13789a747e4fSDavid du Colombier 		if(n == 0 && (chan == cons.srvchan || chan == cons.chan))
13799a747e4fSDavid du Colombier 			continue;
13809a747e4fSDavid du Colombier 		if(n <= 0)
13819a747e4fSDavid du Colombier 			return;
13829a747e4fSDavid du Colombier 		if(convM2S9p1(inbuf, &fi, n) != n){
13839a747e4fSDavid du Colombier 			error9p1(chan, outbuf);
13849a747e4fSDavid du Colombier 			continue;
13859a747e4fSDavid du Colombier 		}
13869a747e4fSDavid du Colombier 
13879a747e4fSDavid du Colombier 		t = fi.type;
13889a747e4fSDavid du Colombier 		if(t < 0 || t >= MAXSYSCALL || (t&1) || !call9p1[t]) {
13899a747e4fSDavid du Colombier 			print("9p1: bad message type\n");
13909a747e4fSDavid du Colombier 			error9p1(chan, outbuf);
13919a747e4fSDavid du Colombier 			continue;
13929a747e4fSDavid du Colombier 		}
13939a747e4fSDavid du Colombier 
13949a747e4fSDavid du Colombier 		if(CHAT(chan))
13959a747e4fSDavid du Colombier 			print("9p1: fi %O\n", &fi);
13969a747e4fSDavid du Colombier 
13979a747e4fSDavid du Colombier 		/*
13989a747e4fSDavid du Colombier 		 * set up reply message
13999a747e4fSDavid du Colombier 		 */
14009a747e4fSDavid du Colombier 		fo.err = 0;
14019a747e4fSDavid du Colombier 		if(t == Tread9p1)
14029a747e4fSDavid du Colombier 			fo.data = (char*)outbuf + 8;
14039a747e4fSDavid du Colombier 
14049a747e4fSDavid du Colombier 		/*
14059a747e4fSDavid du Colombier 		 * call the file system
14069a747e4fSDavid du Colombier 		 */
14079a747e4fSDavid du Colombier 		cons.work.count++;
14089a747e4fSDavid du Colombier 		cons.rate.count += n;
14099a747e4fSDavid du Colombier 
14109a747e4fSDavid du Colombier 		/*
14119a747e4fSDavid du Colombier 		 * call the file system
14129a747e4fSDavid du Colombier 		 */
14139a747e4fSDavid du Colombier 		rlock(&mainlock);
14149a747e4fSDavid du Colombier 		rlock(&chan->reflock);
14159a747e4fSDavid du Colombier 
14169a747e4fSDavid du Colombier 		(*call9p1[t])(chan, &fi, &fo);
14179a747e4fSDavid du Colombier 
14189a747e4fSDavid du Colombier 		runlock(&chan->reflock);
14199a747e4fSDavid du Colombier 		runlock(&mainlock);
14209a747e4fSDavid du Colombier 
14219a747e4fSDavid du Colombier 		fo.type = t+1;
14229a747e4fSDavid du Colombier 		fo.tag = fi.tag;
14239a747e4fSDavid du Colombier 
14249a747e4fSDavid du Colombier 		if(chat)
14259a747e4fSDavid du Colombier 			print("9p1: fo %O\n", &fo);
14269a747e4fSDavid du Colombier 
14279a747e4fSDavid du Colombier 		if(fo.err) {
14289a747e4fSDavid du Colombier 			strcpy(fo.ename, errstring[fo.err]);
14299a747e4fSDavid du Colombier 			if(CHAT(cp))
14309a747e4fSDavid du Colombier 				print("	error: %s\n", fo.ename);
14319a747e4fSDavid du Colombier 			fo.type = Terror9p1+1;
14329a747e4fSDavid du Colombier 		}
14339a747e4fSDavid du Colombier 
14349a747e4fSDavid du Colombier 		n = convS2M9p1(&fo, outbuf);
14359a747e4fSDavid du Colombier 		if(n == 0) {
14369a747e4fSDavid du Colombier 			print("9p1: bad S2M conversion\n");
14379a747e4fSDavid du Colombier 			error9p1(chan, outbuf);
14389a747e4fSDavid du Colombier 			continue;
14399a747e4fSDavid du Colombier 		}
14409a747e4fSDavid du Colombier 
14419a747e4fSDavid du Colombier 		cons.rate.count += n;
14429a747e4fSDavid du Colombier 		send(chan, outbuf, n);
14439a747e4fSDavid du Colombier 	}
14449a747e4fSDavid du Colombier }
1445