xref: /plan9/sys/src/cmd/disk/kfs/9p2.c (revision 12fd1c83b21b4d1deeab2b58fe2c202d2038c714)
19a747e4fSDavid du Colombier #include	"all.h"
29a747e4fSDavid du Colombier 
39a747e4fSDavid du Colombier #define MSIZE	(MAXDAT+128)
49a747e4fSDavid du Colombier 
59a747e4fSDavid du Colombier static void
seterror(Fcall * ou,int err)69a747e4fSDavid du Colombier seterror(Fcall *ou, int err)
79a747e4fSDavid du Colombier {
89a747e4fSDavid du Colombier 
99a747e4fSDavid du Colombier 	if(0 <= err && err < MAXERR)
109a747e4fSDavid du Colombier 		ou->ename = errstring[err];
119a747e4fSDavid du Colombier 	else
129a747e4fSDavid du Colombier 		ou->ename = "unknown error";
139a747e4fSDavid du Colombier }
149a747e4fSDavid du Colombier 
159a747e4fSDavid du Colombier static int
fsversion(Chan * chan,Fcall * f,Fcall * r)169a747e4fSDavid du Colombier fsversion(Chan* chan, Fcall* f, Fcall* r)
179a747e4fSDavid du Colombier {
189a747e4fSDavid du Colombier 	if(f->msize < MSIZE)
199a747e4fSDavid du Colombier 		r->msize = f->msize;
209a747e4fSDavid du Colombier 	else
219a747e4fSDavid du Colombier 		r->msize = MSIZE;
229a747e4fSDavid du Colombier 	/*
239a747e4fSDavid du Colombier 	 * Should check the '.' stuff here.
249a747e4fSDavid du Colombier 	 * What happens if Tversion has already been seen?
259a747e4fSDavid du Colombier 	 */
269a747e4fSDavid du Colombier 	if(strcmp(f->version, VERSION9P) == 0){
279a747e4fSDavid du Colombier 		r->version = VERSION9P;
289a747e4fSDavid du Colombier 		chan->msize = r->msize;
299a747e4fSDavid du Colombier 	}else
309a747e4fSDavid du Colombier 		r->version = "unknown";
319a747e4fSDavid du Colombier 
329a747e4fSDavid du Colombier 	fileinit(chan);
339a747e4fSDavid du Colombier 	return 0;
349a747e4fSDavid du Colombier }
359a747e4fSDavid du Colombier 
36b7b24591SDavid du Colombier char *keyspec = "proto=p9any role=server";
37b7b24591SDavid du Colombier 
389a747e4fSDavid du Colombier static int
fsauth(Chan * chan,Fcall * f,Fcall * r)399a747e4fSDavid du Colombier fsauth(Chan *chan, Fcall *f, Fcall *r)
409a747e4fSDavid du Colombier {
419a747e4fSDavid du Colombier 	int err, fd;
429a747e4fSDavid du Colombier 	char *aname;
439a747e4fSDavid du Colombier 	File *file;
44b7b24591SDavid du Colombier 	int afd;
45b7b24591SDavid du Colombier 	AuthRpc *rpc;
469a747e4fSDavid du Colombier 
479a747e4fSDavid du Colombier 	err = 0;
489a747e4fSDavid du Colombier 	if(chan == cons.srvchan)
499a747e4fSDavid du Colombier 		return Eauthmsg;
509a747e4fSDavid du Colombier 	file = filep(chan, f->afid, 1);
519a747e4fSDavid du Colombier 	if(file == nil)
529a747e4fSDavid du Colombier 		return Efidinuse;
535d459b5aSDavid du Colombier 
545d459b5aSDavid du Colombier 	/* forget any previous authentication */
555d459b5aSDavid du Colombier 	file->cuid = 0;
56b7b24591SDavid du Colombier 
579a747e4fSDavid du Colombier 	if(access("/mnt/factotum", 0) < 0)
589a747e4fSDavid du Colombier 		if((fd = open("/srv/factotum", ORDWR)) >= 0)
599a747e4fSDavid du Colombier 			mount(fd, -1, "/mnt", MBEFORE, "");
60b7b24591SDavid du Colombier 
61b7b24591SDavid du Colombier 	afd = open("/mnt/factotum/rpc", ORDWR);
62b7b24591SDavid du Colombier 	if(afd < 0){
639a747e4fSDavid du Colombier 		err = Esystem;
649a747e4fSDavid du Colombier 		goto out;
659a747e4fSDavid du Colombier 	}
66b7b24591SDavid du Colombier 	rpc = auth_allocrpc(afd);
67b7b24591SDavid du Colombier 	if(rpc == nil){
68b7b24591SDavid du Colombier 		close(afd);
69b7b24591SDavid du Colombier 		err = Esystem;
70b7b24591SDavid du Colombier 		goto out;
71b7b24591SDavid du Colombier 	}
72b7b24591SDavid du Colombier 	file->rpc = rpc;
73b7b24591SDavid du Colombier 	if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){
74b7b24591SDavid du Colombier 		err = Esystem;
75b7b24591SDavid du Colombier 		goto out;
76b7b24591SDavid du Colombier 	}
77b7b24591SDavid du Colombier 
789a747e4fSDavid du Colombier 	aname = f->aname;
799a747e4fSDavid du Colombier 	if(!aname[0])
809a747e4fSDavid du Colombier 		aname = "main";
819a747e4fSDavid du Colombier 	file->fs = fsstr(aname);
829a747e4fSDavid du Colombier 	if(file->fs == nil){
839a747e4fSDavid du Colombier 		err = Ebadspc;
849a747e4fSDavid du Colombier 		goto out;
859a747e4fSDavid du Colombier 	}
869a747e4fSDavid du Colombier 	file->uid = strtouid(f->uname);
879a747e4fSDavid du Colombier 	if(file->uid < 0){
889a747e4fSDavid du Colombier 		err = Ebadu;
899a747e4fSDavid du Colombier 		goto out;
909a747e4fSDavid du Colombier 	}
919a747e4fSDavid du Colombier 	file->qid.path = 0;
929a747e4fSDavid du Colombier 	file->qid.vers = 0;
939a747e4fSDavid du Colombier 	file->qid.type = QTAUTH;
949a747e4fSDavid du Colombier 	r->qid = file->qid;
959a747e4fSDavid du Colombier 
969a747e4fSDavid du Colombier out:
979a747e4fSDavid du Colombier 	if(file != nil){
989a747e4fSDavid du Colombier 		qunlock(file);
999a747e4fSDavid du Colombier 		if(err != 0)
1009a747e4fSDavid du Colombier 			freefp(file);
1019a747e4fSDavid du Colombier 	}
1029a747e4fSDavid du Colombier 	return err;
1039a747e4fSDavid du Colombier }
1049a747e4fSDavid du Colombier 
105b7b24591SDavid du Colombier int
authread(File * file,uchar * data,int count)106b7b24591SDavid du Colombier authread(File *file, uchar *data, int count)
107b7b24591SDavid du Colombier {
108b7b24591SDavid du Colombier 	AuthInfo *ai;
109b7b24591SDavid du Colombier 	AuthRpc *rpc;
110b7b24591SDavid du Colombier 	int rv;
111b7b24591SDavid du Colombier 
112b7b24591SDavid du Colombier 	rpc = file->rpc;
1135d459b5aSDavid du Colombier 	if(rpc == nil)
1145d459b5aSDavid du Colombier 		return -1;
1155d459b5aSDavid du Colombier 
116b7b24591SDavid du Colombier 	rv = auth_rpc(rpc, "read", nil, 0);
117b7b24591SDavid du Colombier 	switch(rv){
118b7b24591SDavid du Colombier 	case ARdone:
119b7b24591SDavid du Colombier 		ai = auth_getinfo(rpc);
120b7b24591SDavid du Colombier 		if(ai == nil)
121b7b24591SDavid du Colombier 			return -1;
122b7b24591SDavid du Colombier 		if(chat)
123b7b24591SDavid du Colombier 			print("authread identifies user as %s\n", ai->cuid);
124b7b24591SDavid du Colombier 		file->cuid = strtouid(ai->cuid);
1255d459b5aSDavid du Colombier 		auth_freeAI(ai);
126b7b24591SDavid du Colombier 		if(file->cuid == 0)
127b7b24591SDavid du Colombier 			return -1;
128b7b24591SDavid du Colombier 		if(chat)
129b7b24591SDavid du Colombier 			print("%s is a known user\n", ai->cuid);
130b7b24591SDavid du Colombier 		return 0;
131b7b24591SDavid du Colombier 	case ARok:
132b7b24591SDavid du Colombier 		if(count < rpc->narg)
133b7b24591SDavid du Colombier 			return -1;
134b7b24591SDavid du Colombier 		memmove(data, rpc->arg, rpc->narg);
135b7b24591SDavid du Colombier 		return rpc->narg;
136b7b24591SDavid du Colombier 	case ARphase:
137b7b24591SDavid du Colombier 		return -1;
138b7b24591SDavid du Colombier 	default:
139b7b24591SDavid du Colombier 		return -1;
140b7b24591SDavid du Colombier 	}
141b7b24591SDavid du Colombier }
142b7b24591SDavid du Colombier 
143b7b24591SDavid du Colombier int
authwrite(File * file,uchar * data,int count)144b7b24591SDavid du Colombier authwrite(File *file, uchar *data, int count)
145b7b24591SDavid du Colombier {
146b7b24591SDavid du Colombier 	int ret;
147b7b24591SDavid du Colombier 
148b7b24591SDavid du Colombier 	ret = auth_rpc(file->rpc, "write", data, count);
149b7b24591SDavid du Colombier 	if(ret != ARok)
150b7b24591SDavid du Colombier 		return -1;
151b7b24591SDavid du Colombier 	return count;
152b7b24591SDavid du Colombier }
153b7b24591SDavid du Colombier 
1549a747e4fSDavid du Colombier void
mkqid9p1(Qid9p1 * qid9p1,Qid * qid)1559a747e4fSDavid du Colombier mkqid9p1(Qid9p1* qid9p1, Qid* qid)
1569a747e4fSDavid du Colombier {
1579a747e4fSDavid du Colombier 	if(qid->path & 0xFFFFFFFF00000000LL)
1589a747e4fSDavid du Colombier 		panic("mkqid9p1: path %lluX\n", qid->path);
1599a747e4fSDavid du Colombier 	qid9p1->path = qid->path & 0xFFFFFFFF;
1609a747e4fSDavid du Colombier 	if(qid->type & QTDIR)
1619a747e4fSDavid du Colombier 		qid9p1->path |= QPDIR;
1629a747e4fSDavid du Colombier 	qid9p1->version = qid->vers;
1639a747e4fSDavid du Colombier }
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier void
authfree(File * fp)166b7b24591SDavid du Colombier authfree(File *fp)
167b7b24591SDavid du Colombier {
168b7b24591SDavid du Colombier 	if(fp->rpc != nil){
169b7b24591SDavid du Colombier 		close(fp->rpc->afd);
170b7b24591SDavid du Colombier 		free(fp->rpc);
171b7b24591SDavid du Colombier 		fp->rpc = nil;
172b7b24591SDavid du Colombier 	}
173b7b24591SDavid du Colombier }
174b7b24591SDavid du Colombier 
175b7b24591SDavid du Colombier void
mkqid9p2(Qid * qid,Qid9p1 * qid9p1,int mode)1769a747e4fSDavid du Colombier mkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode)
1779a747e4fSDavid du Colombier {
1789a747e4fSDavid du Colombier 	qid->path = (ulong)(qid9p1->path & ~QPDIR);
1799a747e4fSDavid du Colombier 	qid->vers = qid9p1->version;
1809a747e4fSDavid du Colombier 	qid->type = 0;
1819a747e4fSDavid du Colombier 	if(mode & DDIR)
1829a747e4fSDavid du Colombier 		qid->type |= QTDIR;
1839a747e4fSDavid du Colombier 	if(mode & DAPND)
1849a747e4fSDavid du Colombier 		qid->type |= QTAPPEND;
1859a747e4fSDavid du Colombier 	if(mode & DLOCK)
1869a747e4fSDavid du Colombier 		qid->type |= QTEXCL;
1879a747e4fSDavid du Colombier }
1889a747e4fSDavid du Colombier 
1899a747e4fSDavid du Colombier static int
checkattach(Chan * chan,File * afile,File * file,Filsys * fs)1909a747e4fSDavid du Colombier checkattach(Chan *chan, File *afile, File *file, Filsys *fs)
1919a747e4fSDavid du Colombier {
192b7b24591SDavid du Colombier 	uchar buf[1];
1939a747e4fSDavid du Colombier 
1949a747e4fSDavid du Colombier 	if(chan == cons.srvchan || chan == cons.chan)
1959a747e4fSDavid du Colombier 		return 0;
196b7b24591SDavid du Colombier 
197b7b24591SDavid du Colombier 	/* if no afile, this had better be none */
198b7b24591SDavid du Colombier 	if(afile == nil){
1999a747e4fSDavid du Colombier 		if(file->uid == 0){
2009a747e4fSDavid du Colombier 			if(!allownone && !chan->authed)
2019a747e4fSDavid du Colombier 				return Eauth;
2029a747e4fSDavid du Colombier 			return 0;
2039a747e4fSDavid du Colombier 		}
2049a747e4fSDavid du Colombier 		return Eauth;
205b7b24591SDavid du Colombier 	}
206b7b24591SDavid du Colombier 
207b7b24591SDavid du Colombier 	/* otherwise, we'ld better have a usable cuid */
2089a747e4fSDavid du Colombier 	if(!(afile->qid.type&QTAUTH))
2099a747e4fSDavid du Colombier 		return Eauth;
2109a747e4fSDavid du Colombier 	if(afile->uid != file->uid || afile->fs != fs)
2119a747e4fSDavid du Colombier 		return Eauth;
212b7b24591SDavid du Colombier 	if(afile->cuid <= 0){
213b7b24591SDavid du Colombier 		if(authread(afile, buf, 0) != 0)
2149a747e4fSDavid du Colombier 			return Eauth;
215b7b24591SDavid du Colombier 		if(afile->cuid <= 0)
216b7b24591SDavid du Colombier 			return Eauth;
217b7b24591SDavid du Colombier 	}
218b7b24591SDavid du Colombier 	file->uid = afile->cuid;
2195d459b5aSDavid du Colombier 
2205d459b5aSDavid du Colombier 	/* once someone has authenticated on the channel, others can become none */
2219a747e4fSDavid du Colombier 	chan->authed = 1;
222b7b24591SDavid du Colombier 
2239a747e4fSDavid du Colombier 	return 0;
2249a747e4fSDavid du Colombier }
2259a747e4fSDavid du Colombier 
2269a747e4fSDavid du Colombier static int
fsattach(Chan * chan,Fcall * f,Fcall * r)2279a747e4fSDavid du Colombier fsattach(Chan* chan, Fcall* f, Fcall* r)
2289a747e4fSDavid du Colombier {
2299a747e4fSDavid du Colombier 	char *aname;
2309a747e4fSDavid du Colombier 	Iobuf *p;
2319a747e4fSDavid du Colombier 	Dentry *d;
2329a747e4fSDavid du Colombier 	File *file;
2339a747e4fSDavid du Colombier 	File *afile;
2349a747e4fSDavid du Colombier 	Filsys *fs;
2359a747e4fSDavid du Colombier 	long raddr;
2369a747e4fSDavid du Colombier 	int error, u;
2379a747e4fSDavid du Colombier 
2389a747e4fSDavid du Colombier 	aname = f->aname;
2399a747e4fSDavid du Colombier 	if(!aname[0])	/* default */
2409a747e4fSDavid du Colombier 		aname = "main";
2419a747e4fSDavid du Colombier 	p = nil;
2429a747e4fSDavid du Colombier 	afile = filep(chan, f->afid, 0);
2439a747e4fSDavid du Colombier 	file = filep(chan, f->fid, 1);
2449a747e4fSDavid du Colombier 	if(file == nil){
2459a747e4fSDavid du Colombier 		error = Efidinuse;
2469a747e4fSDavid du Colombier 		goto out;
2479a747e4fSDavid du Colombier 	}
2489a747e4fSDavid du Colombier 
2499a747e4fSDavid du Colombier 	u = -1;
2509a747e4fSDavid du Colombier 	if(chan != cons.chan){
2519a747e4fSDavid du Colombier 		if(strcmp(f->uname, "adm") == 0){
2529a747e4fSDavid du Colombier 			error = Eauth;
2539a747e4fSDavid du Colombier 			goto out;
2549a747e4fSDavid du Colombier 		}
2559a747e4fSDavid du Colombier 		u = strtouid(f->uname);
2569a747e4fSDavid du Colombier 		if(u < 0){
2579a747e4fSDavid du Colombier 			error = Ebadu;
2589a747e4fSDavid du Colombier 			goto out;
2599a747e4fSDavid du Colombier 		}
2609a747e4fSDavid du Colombier 	}
2619a747e4fSDavid du Colombier 	file->uid = u;
2629a747e4fSDavid du Colombier 
2639a747e4fSDavid du Colombier 	fs = fsstr(aname);
2649a747e4fSDavid du Colombier 	if(fs == nil){
2659a747e4fSDavid du Colombier 		error = Ebadspc;
2669a747e4fSDavid du Colombier 		goto out;
2679a747e4fSDavid du Colombier 	}
2689a747e4fSDavid du Colombier 
2699a747e4fSDavid du Colombier 	if(error = checkattach(chan, afile, file, fs))
2709a747e4fSDavid du Colombier 		goto out;
2719a747e4fSDavid du Colombier 
2729a747e4fSDavid du Colombier 	raddr = getraddr(fs->dev);
2739a747e4fSDavid du Colombier 	p = getbuf(fs->dev, raddr, Bread);
2749a747e4fSDavid du Colombier 	d = getdir(p, 0);
2759a747e4fSDavid du Colombier 	if(d == nil || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)){
2769a747e4fSDavid du Colombier 		error = Ealloc;
2779a747e4fSDavid du Colombier 		goto out;
2789a747e4fSDavid du Colombier 	}
2799a747e4fSDavid du Colombier 	if(iaccess(file, d, DEXEC)){
2809a747e4fSDavid du Colombier 		error = Eaccess;
2819a747e4fSDavid du Colombier 		goto out;
2829a747e4fSDavid du Colombier 	}
2839a747e4fSDavid du Colombier 	if(file->uid == 0 && isro(fs->dev)) {
2849a747e4fSDavid du Colombier 		/*
2859a747e4fSDavid du Colombier 		 * 'none' not allowed on dump
2869a747e4fSDavid du Colombier 		 */
2879a747e4fSDavid du Colombier 		error = Eaccess;
2889a747e4fSDavid du Colombier 		goto out;
2899a747e4fSDavid du Colombier 	}
2909a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
2919a747e4fSDavid du Colombier 	mkqid(&file->qid, d, 1);
2929a747e4fSDavid du Colombier 	file->fs = fs;
2939a747e4fSDavid du Colombier 	file->addr = raddr;
2949a747e4fSDavid du Colombier 	file->slot = 0;
2959a747e4fSDavid du Colombier 	file->open = 0;
2969a747e4fSDavid du Colombier 	freewp(file->wpath);
2979a747e4fSDavid du Colombier 	file->wpath = 0;
2989a747e4fSDavid du Colombier 
2999a747e4fSDavid du Colombier 	r->qid = file->qid;
3009a747e4fSDavid du Colombier 
3019a747e4fSDavid du Colombier //	if(cons.flags & attachflag)
3029a747e4fSDavid du Colombier //		print("9p2: attach %s %T to \"%s\" C%d\n",
3039a747e4fSDavid du Colombier //			chan->whoname, chan->whotime, fs->name, chan->chan);
3049a747e4fSDavid du Colombier 
3059a747e4fSDavid du Colombier out:
3069a747e4fSDavid du Colombier //	if((cons.flags & attachflag) && error)
3079a747e4fSDavid du Colombier //		print("9p2: attach %s %T SUCK EGGS --- %s\n",
3089a747e4fSDavid du Colombier //			f->uname, time(), errstr[error]);
3099a747e4fSDavid du Colombier 	if(p != nil)
3109a747e4fSDavid du Colombier 		putbuf(p);
3119a747e4fSDavid du Colombier 	if(afile != nil)
3129a747e4fSDavid du Colombier 		qunlock(afile);
3139a747e4fSDavid du Colombier 	if(file != nil){
3149a747e4fSDavid du Colombier 		qunlock(file);
3159a747e4fSDavid du Colombier 		if(error)
3169a747e4fSDavid du Colombier 			freefp(file);
3179a747e4fSDavid du Colombier 	}
3189a747e4fSDavid du Colombier 
3199a747e4fSDavid du Colombier 	return error;
3209a747e4fSDavid du Colombier }
3219a747e4fSDavid du Colombier 
3229a747e4fSDavid du Colombier static int
fsflush(Chan * chan,Fcall *,Fcall *)3239a747e4fSDavid du Colombier fsflush(Chan* chan, Fcall*, Fcall*)
3249a747e4fSDavid du Colombier {
3259a747e4fSDavid du Colombier 	runlock(&chan->reflock);
3269a747e4fSDavid du Colombier 	wlock(&chan->reflock);
3279a747e4fSDavid du Colombier 	wunlock(&chan->reflock);
3289a747e4fSDavid du Colombier 	rlock(&chan->reflock);
3299a747e4fSDavid du Colombier 
3309a747e4fSDavid du Colombier 	return 0;
3319a747e4fSDavid du Colombier }
3329a747e4fSDavid du Colombier 
3339a747e4fSDavid du Colombier static void
clone(File * nfile,File * file)3349a747e4fSDavid du Colombier clone(File* nfile, File* file)
3359a747e4fSDavid du Colombier {
3369a747e4fSDavid du Colombier 	Wpath *wpath;
3379a747e4fSDavid du Colombier 
3389a747e4fSDavid du Colombier 	nfile->qid = file->qid;
3399a747e4fSDavid du Colombier 
3409a747e4fSDavid du Colombier 	lock(&wpathlock);
3419a747e4fSDavid du Colombier 	nfile->wpath = file->wpath;
3429a747e4fSDavid du Colombier 	for(wpath = nfile->wpath; wpath != nil; wpath = wpath->up)
3439a747e4fSDavid du Colombier 		wpath->refs++;
3449a747e4fSDavid du Colombier 	unlock(&wpathlock);
3459a747e4fSDavid du Colombier 
3469a747e4fSDavid du Colombier 	nfile->fs = file->fs;
3479a747e4fSDavid du Colombier 	nfile->addr = file->addr;
3489a747e4fSDavid du Colombier 	nfile->slot = file->slot;
3499a747e4fSDavid du Colombier 	nfile->uid = file->uid;
3505d459b5aSDavid du Colombier 	nfile->cuid = 0;
3519a747e4fSDavid du Colombier 	nfile->open = file->open & ~FREMOV;
3529a747e4fSDavid du Colombier }
3539a747e4fSDavid du Colombier 
3549a747e4fSDavid du Colombier static int
walkname(File * file,char * wname,Qid * wqid)3559a747e4fSDavid du Colombier walkname(File* file, char* wname, Qid* wqid)
3569a747e4fSDavid du Colombier {
3579a747e4fSDavid du Colombier 	Wpath *w;
3589a747e4fSDavid du Colombier 	Iobuf *p, *p1;
3599a747e4fSDavid du Colombier 	Dentry *d, *d1;
3609a747e4fSDavid du Colombier 	int error, slot;
3619a747e4fSDavid du Colombier 	long addr, qpath;
3629a747e4fSDavid du Colombier 
3639a747e4fSDavid du Colombier 	p = p1 = nil;
3649a747e4fSDavid du Colombier 
3659a747e4fSDavid du Colombier 	/*
3669a747e4fSDavid du Colombier 	 * File must not have been opened for I/O by an open
3679a747e4fSDavid du Colombier 	 * or create message and must represent a directory.
3689a747e4fSDavid du Colombier 	 */
3699a747e4fSDavid du Colombier 	if(file->open != 0){
3709a747e4fSDavid du Colombier 		error = Emode;
3719a747e4fSDavid du Colombier 		goto out;
3729a747e4fSDavid du Colombier 	}
3739a747e4fSDavid du Colombier 
3749a747e4fSDavid du Colombier 	p = getbuf(file->fs->dev, file->addr, Bread);
3759a747e4fSDavid du Colombier 	if(p == nil || checktag(p, Tdir, QPNONE)){
3769a747e4fSDavid du Colombier 		error = Edir1;
3779a747e4fSDavid du Colombier 		goto out;
3789a747e4fSDavid du Colombier 	}
3799a747e4fSDavid du Colombier 	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
3809a747e4fSDavid du Colombier 		error = Ealloc;
3819a747e4fSDavid du Colombier 		goto out;
3829a747e4fSDavid du Colombier 	}
3839a747e4fSDavid du Colombier 	if(!(d->mode & DDIR)){
3849a747e4fSDavid du Colombier 		error = Edir1;
3859a747e4fSDavid du Colombier 		goto out;
3869a747e4fSDavid du Colombier 	}
3879a747e4fSDavid du Colombier 	if(error = mkqidcmp(&file->qid, d))
3889a747e4fSDavid du Colombier 		goto out;
3899a747e4fSDavid du Colombier 
3909a747e4fSDavid du Colombier 	/*
3919a747e4fSDavid du Colombier 	 * For walked elements the implied user must
3929a747e4fSDavid du Colombier 	 * have permission to search the directory.
3939a747e4fSDavid du Colombier 	 */
3949a747e4fSDavid du Colombier 	if(file->cp != cons.chan && iaccess(file, d, DEXEC)){
3959a747e4fSDavid du Colombier 		error = Eaccess;
3969a747e4fSDavid du Colombier 		goto out;
3979a747e4fSDavid du Colombier 	}
3989a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
3999a747e4fSDavid du Colombier 
4009a747e4fSDavid du Colombier 	if(strcmp(wname, ".") == 0){
4019a747e4fSDavid du Colombier setdot:
4029a747e4fSDavid du Colombier 		if(wqid != nil)
4039a747e4fSDavid du Colombier 			*wqid = file->qid;
4049a747e4fSDavid du Colombier 		goto out;
4059a747e4fSDavid du Colombier 	}
4069a747e4fSDavid du Colombier 	if(strcmp(wname, "..") == 0){
4079a747e4fSDavid du Colombier 		if(file->wpath == 0)
4089a747e4fSDavid du Colombier 			goto setdot;
4099a747e4fSDavid du Colombier 		putbuf(p);
4109a747e4fSDavid du Colombier 		p = nil;
4119a747e4fSDavid du Colombier 		addr = file->wpath->addr;
4129a747e4fSDavid du Colombier 		slot = file->wpath->slot;
4139a747e4fSDavid du Colombier 		p1 = getbuf(file->fs->dev, addr, Bread);
4149a747e4fSDavid du Colombier 		if(p1 == nil || checktag(p1, Tdir, QPNONE)){
4159a747e4fSDavid du Colombier 			error = Edir1;
4169a747e4fSDavid du Colombier 			goto out;
4179a747e4fSDavid du Colombier 		}
4189a747e4fSDavid du Colombier 		if((d1 = getdir(p1, slot)) == nil || !(d1->mode & DALLOC)){
4199a747e4fSDavid du Colombier 			error = Ephase;
4209a747e4fSDavid du Colombier 			goto out;
4219a747e4fSDavid du Colombier 		}
4229a747e4fSDavid du Colombier 		lock(&wpathlock);
4239a747e4fSDavid du Colombier 		file->wpath->refs--;
4249a747e4fSDavid du Colombier 		file->wpath = file->wpath->up;
4259a747e4fSDavid du Colombier 		unlock(&wpathlock);
4269a747e4fSDavid du Colombier 		goto found;
4279a747e4fSDavid du Colombier 	}
4289a747e4fSDavid du Colombier 
4299a747e4fSDavid du Colombier 	for(addr = 0; ; addr++){
4309a747e4fSDavid du Colombier 		if(p == nil){
4319a747e4fSDavid du Colombier 			p = getbuf(file->fs->dev, file->addr, Bread);
4329a747e4fSDavid du Colombier 			if(p == nil || checktag(p, Tdir, QPNONE)){
4339a747e4fSDavid du Colombier 				error = Ealloc;
4349a747e4fSDavid du Colombier 				goto out;
4359a747e4fSDavid du Colombier 			}
4369a747e4fSDavid du Colombier 			d = getdir(p, file->slot);
4379a747e4fSDavid du Colombier 			if(d == nil ||  !(d->mode & DALLOC)){
4389a747e4fSDavid du Colombier 				error = Ealloc;
4399a747e4fSDavid du Colombier 				goto out;
4409a747e4fSDavid du Colombier 			}
4419a747e4fSDavid du Colombier 		}
4429a747e4fSDavid du Colombier 		qpath = d->qid.path;
4439a747e4fSDavid du Colombier 		p1 = dnodebuf1(p, d, addr, 0);
4449a747e4fSDavid du Colombier 		p = nil;
4459a747e4fSDavid du Colombier 		if(p1 == nil || checktag(p1, Tdir, qpath)){
4469a747e4fSDavid du Colombier 			error = Eentry;
4479a747e4fSDavid du Colombier 			goto out;
4489a747e4fSDavid du Colombier 		}
4499a747e4fSDavid du Colombier 		for(slot = 0; slot < DIRPERBUF; slot++){
4509a747e4fSDavid du Colombier 			d1 = getdir(p1, slot);
4519a747e4fSDavid du Colombier 			if(!(d1->mode & DALLOC))
4529a747e4fSDavid du Colombier 				continue;
4539a747e4fSDavid du Colombier 			if(strncmp(wname, d1->name, NAMELEN) != 0)
4549a747e4fSDavid du Colombier 				continue;
4559a747e4fSDavid du Colombier 			/*
4569a747e4fSDavid du Colombier 			 * update walk path
4579a747e4fSDavid du Colombier 			 */
4589a747e4fSDavid du Colombier 			if((w = newwp()) == nil){
4599a747e4fSDavid du Colombier 				error = Ewalk;
4609a747e4fSDavid du Colombier 				goto out;
4619a747e4fSDavid du Colombier 			}
4629a747e4fSDavid du Colombier 			w->addr = file->addr;
4639a747e4fSDavid du Colombier 			w->slot = file->slot;
4649a747e4fSDavid du Colombier 			w->up = file->wpath;
4659a747e4fSDavid du Colombier 			file->wpath = w;
4669a747e4fSDavid du Colombier 			slot += DIRPERBUF*addr;
4679a747e4fSDavid du Colombier 			goto found;
4689a747e4fSDavid du Colombier 		}
4699a747e4fSDavid du Colombier 		putbuf(p1);
4709a747e4fSDavid du Colombier 		p1 = nil;
4719a747e4fSDavid du Colombier 	}
4729a747e4fSDavid du Colombier 
4739a747e4fSDavid du Colombier found:
4749a747e4fSDavid du Colombier 	file->addr = p1->addr;
4759a747e4fSDavid du Colombier 	mkqid(&file->qid, d1, 1);
4769a747e4fSDavid du Colombier 	putbuf(p1);
4779a747e4fSDavid du Colombier 	p1 = nil;
4789a747e4fSDavid du Colombier 	file->slot = slot;
4799a747e4fSDavid du Colombier 	if(wqid != nil)
4809a747e4fSDavid du Colombier 		*wqid = file->qid;
4819a747e4fSDavid du Colombier 
4829a747e4fSDavid du Colombier out:
4839a747e4fSDavid du Colombier 	if(p1 != nil)
4849a747e4fSDavid du Colombier 		putbuf(p1);
4859a747e4fSDavid du Colombier 	if(p != nil)
4869a747e4fSDavid du Colombier 		putbuf(p);
4879a747e4fSDavid du Colombier 
4889a747e4fSDavid du Colombier 	return error;
4899a747e4fSDavid du Colombier }
4909a747e4fSDavid du Colombier 
4919a747e4fSDavid du Colombier static int
fswalk(Chan * chan,Fcall * f,Fcall * r)4929a747e4fSDavid du Colombier fswalk(Chan* chan, Fcall* f, Fcall* r)
4939a747e4fSDavid du Colombier {
4949a747e4fSDavid du Colombier 	int error, nwname;
4959a747e4fSDavid du Colombier 	File *file, *nfile, tfile;
4969a747e4fSDavid du Colombier 
4979a747e4fSDavid du Colombier 	/*
4989a747e4fSDavid du Colombier 	 * The file identified by f->fid must be valid in the
4999a747e4fSDavid du Colombier 	 * current session and must not have been opened for I/O
5009a747e4fSDavid du Colombier 	 * by an open or create message.
5019a747e4fSDavid du Colombier 	 */
5029a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil)
5039a747e4fSDavid du Colombier 		return Efid;
5049a747e4fSDavid du Colombier 	if(file->open != 0){
5059a747e4fSDavid du Colombier 		qunlock(file);
5069a747e4fSDavid du Colombier 		return Emode;
5079a747e4fSDavid du Colombier 	}
5089a747e4fSDavid du Colombier 
5099a747e4fSDavid du Colombier 	/*
5109a747e4fSDavid du Colombier 	 * If newfid is not the same as fid, allocate a new file;
5119a747e4fSDavid du Colombier 	 * a side effect is checking newfid is not already in use (error);
5129a747e4fSDavid du Colombier 	 * if there are no names to walk this will be equivalent to a
5139a747e4fSDavid du Colombier 	 * simple 'clone' operation.
5149a747e4fSDavid du Colombier 	 * Otherwise, fid and newfid are the same and if there are names
5159a747e4fSDavid du Colombier 	 * to walk make a copy of 'file' to be used during the walk as
5169a747e4fSDavid du Colombier 	 * 'file' must only be updated on success.
5179a747e4fSDavid du Colombier 	 * Finally, it's a no-op if newfid is the same as fid and f->nwname
5189a747e4fSDavid du Colombier 	 * is 0.
5199a747e4fSDavid du Colombier 	 */
5209a747e4fSDavid du Colombier 	r->nwqid = 0;
5219a747e4fSDavid du Colombier 	if(f->newfid != f->fid){
5229a747e4fSDavid du Colombier 		if((nfile = filep(chan, f->newfid, 1)) == nil){
5239a747e4fSDavid du Colombier 			qunlock(file);
5249a747e4fSDavid du Colombier 			return Efidinuse;
5259a747e4fSDavid du Colombier 		}
5269a747e4fSDavid du Colombier 	}
5279a747e4fSDavid du Colombier 	else if(f->nwname != 0){
5289a747e4fSDavid du Colombier 		nfile = &tfile;
5299a747e4fSDavid du Colombier 		memset(nfile, 0, sizeof(File));
5309a747e4fSDavid du Colombier 		nfile->cp = chan;
5319a747e4fSDavid du Colombier 		nfile->fid = ~0;
5329a747e4fSDavid du Colombier 	}
5339a747e4fSDavid du Colombier 	else{
5349a747e4fSDavid du Colombier 		qunlock(file);
5359a747e4fSDavid du Colombier 		return 0;
5369a747e4fSDavid du Colombier 	}
5379a747e4fSDavid du Colombier 	clone(nfile, file);
5389a747e4fSDavid du Colombier 
5399a747e4fSDavid du Colombier 	/*
5409a747e4fSDavid du Colombier 	 * Should check name is not too long.
5419a747e4fSDavid du Colombier 	 */
5429a747e4fSDavid du Colombier 	error = 0;
5439a747e4fSDavid du Colombier 	for(nwname = 0; nwname < f->nwname; nwname++){
5449a747e4fSDavid du Colombier 		error = walkname(nfile, f->wname[nwname], &r->wqid[r->nwqid]);
5459a747e4fSDavid du Colombier 		if(error != 0 || ++r->nwqid >= MAXDAT/sizeof(Qid))
5469a747e4fSDavid du Colombier 			break;
5479a747e4fSDavid du Colombier 	}
5489a747e4fSDavid du Colombier 
5499a747e4fSDavid du Colombier 	if(f->nwname == 0){
5509a747e4fSDavid du Colombier 		/*
5519a747e4fSDavid du Colombier 		 * Newfid must be different to fid (see above)
5529a747e4fSDavid du Colombier 		 * so this is a simple 'clone' operation - there's
5539a747e4fSDavid du Colombier 		 * nothing to do except unlock unless there's
5549a747e4fSDavid du Colombier 		 * an error.
5559a747e4fSDavid du Colombier 		 */
5569a747e4fSDavid du Colombier 		if(error){
5579a747e4fSDavid du Colombier 			freewp(nfile->wpath);
5589a747e4fSDavid du Colombier 			qunlock(nfile);
5599a747e4fSDavid du Colombier 			freefp(nfile);
5609a747e4fSDavid du Colombier 		}
5619a747e4fSDavid du Colombier 		else
5629a747e4fSDavid du Colombier 			qunlock(nfile);
5639a747e4fSDavid du Colombier 	}
5649a747e4fSDavid du Colombier 	else if(r->nwqid < f->nwname){
5659a747e4fSDavid du Colombier 		/*
5669a747e4fSDavid du Colombier 		 * Didn't walk all elements, 'clunk' nfile
5679a747e4fSDavid du Colombier 		 * and leave 'file' alone.
5689a747e4fSDavid du Colombier 		 * Clear error if some of the elements were
5699a747e4fSDavid du Colombier 		 * walked OK.
5709a747e4fSDavid du Colombier 		 */
5719a747e4fSDavid du Colombier 		freewp(nfile->wpath);
5729a747e4fSDavid du Colombier 		if(nfile != &tfile){
5739a747e4fSDavid du Colombier 			qunlock(nfile);
5749a747e4fSDavid du Colombier 			freefp(nfile);
5759a747e4fSDavid du Colombier 		}
5769a747e4fSDavid du Colombier 		if(r->nwqid != 0)
5779a747e4fSDavid du Colombier 			error = 0;
5789a747e4fSDavid du Colombier 	}
5799a747e4fSDavid du Colombier 	else{
5809a747e4fSDavid du Colombier 		/*
5819a747e4fSDavid du Colombier 		 * Walked all elements. If newfid is the same
5829a747e4fSDavid du Colombier 		 * as fid must update 'file' from the temporary
5839a747e4fSDavid du Colombier 		 * copy used during the walk.
5849a747e4fSDavid du Colombier 		 * Otherwise just unlock (when using tfile there's
5859a747e4fSDavid du Colombier 		 * no need to unlock as it's a local).
5869a747e4fSDavid du Colombier 		 */
5879a747e4fSDavid du Colombier 		if(nfile == &tfile){
5889a747e4fSDavid du Colombier 			file->qid = nfile->qid;
5899a747e4fSDavid du Colombier 			freewp(file->wpath);
5909a747e4fSDavid du Colombier 			file->wpath = nfile->wpath;
5919a747e4fSDavid du Colombier 			file->addr = nfile->addr;
5929a747e4fSDavid du Colombier 			file->slot = nfile->slot;
5939a747e4fSDavid du Colombier 		}
5949a747e4fSDavid du Colombier 		else
5959a747e4fSDavid du Colombier 			qunlock(nfile);
5969a747e4fSDavid du Colombier 	}
5979a747e4fSDavid du Colombier 	qunlock(file);
5989a747e4fSDavid du Colombier 
5999a747e4fSDavid du Colombier 	return error;
6009a747e4fSDavid du Colombier }
6019a747e4fSDavid du Colombier 
6029a747e4fSDavid du Colombier static int
fsopen(Chan * chan,Fcall * f,Fcall * r)6039a747e4fSDavid du Colombier fsopen(Chan* chan, Fcall* f, Fcall* r)
6049a747e4fSDavid du Colombier {
6059a747e4fSDavid du Colombier 	Iobuf *p;
6069a747e4fSDavid du Colombier 	Dentry *d;
6079a747e4fSDavid du Colombier 	File *file;
6089a747e4fSDavid du Colombier 	Tlock *t;
6099a747e4fSDavid du Colombier 	Qid qid;
6109a747e4fSDavid du Colombier 	int error, ro, fmod, wok;
6119a747e4fSDavid du Colombier 
6129a747e4fSDavid du Colombier 	wok = 0;
6139a747e4fSDavid du Colombier 	p = nil;
6149a747e4fSDavid du Colombier 
6159a747e4fSDavid du Colombier 	if(chan == cons.chan || writeallow)
6169a747e4fSDavid du Colombier 		wok = 1;
6179a747e4fSDavid du Colombier 
6189a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil){
6199a747e4fSDavid du Colombier 		error = Efid;
6209a747e4fSDavid du Colombier 		goto out;
6219a747e4fSDavid du Colombier 	}
6229a747e4fSDavid du Colombier 
6239a747e4fSDavid du Colombier 	/*
6249a747e4fSDavid du Colombier 	 * if remove on close, check access here
6259a747e4fSDavid du Colombier 	 */
6265d459b5aSDavid du Colombier 	ro = isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup));
6279a747e4fSDavid du Colombier 	if(f->mode & ORCLOSE){
6289a747e4fSDavid du Colombier 		if(ro){
6299a747e4fSDavid du Colombier 			error = Eronly;
6309a747e4fSDavid du Colombier 			goto out;
6319a747e4fSDavid du Colombier 		}
6329a747e4fSDavid du Colombier 		/*
6339a747e4fSDavid du Colombier 		 * check on parent directory of file to be deleted
6349a747e4fSDavid du Colombier 		 */
6359a747e4fSDavid du Colombier 		if(file->wpath == 0 || file->wpath->addr == file->addr){
6369a747e4fSDavid du Colombier 			error = Ephase;
6379a747e4fSDavid du Colombier 			goto out;
6389a747e4fSDavid du Colombier 		}
6399a747e4fSDavid du Colombier 		p = getbuf(file->fs->dev, file->wpath->addr, Bread);
6409a747e4fSDavid du Colombier 		if(p == nil || checktag(p, Tdir, QPNONE)){
6419a747e4fSDavid du Colombier 			error = Ephase;
6429a747e4fSDavid du Colombier 			goto out;
6439a747e4fSDavid du Colombier 		}
6449a747e4fSDavid du Colombier 		if((d = getdir(p, file->wpath->slot)) == nil || !(d->mode & DALLOC)){
6459a747e4fSDavid du Colombier 			error = Ephase;
6469a747e4fSDavid du Colombier 			goto out;
6479a747e4fSDavid du Colombier 		}
6489a747e4fSDavid du Colombier 		if(iaccess(file, d, DWRITE)){
6499a747e4fSDavid du Colombier 			error = Eaccess;
6509a747e4fSDavid du Colombier 			goto out;
6519a747e4fSDavid du Colombier 		}
6529a747e4fSDavid du Colombier 		putbuf(p);
6539a747e4fSDavid du Colombier 	}
6549a747e4fSDavid du Colombier 	p = getbuf(file->fs->dev, file->addr, Bread);
6559a747e4fSDavid du Colombier 	if(p == nil || checktag(p, Tdir, QPNONE)){
6569a747e4fSDavid du Colombier 		error = Ealloc;
6579a747e4fSDavid du Colombier 		goto out;
6589a747e4fSDavid du Colombier 	}
6599a747e4fSDavid du Colombier 	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
6609a747e4fSDavid du Colombier 		error = Ealloc;
6619a747e4fSDavid du Colombier 		goto out;
6629a747e4fSDavid du Colombier 	}
6639a747e4fSDavid du Colombier 	if(error = mkqidcmp(&file->qid, d))
6649a747e4fSDavid du Colombier 		goto out;
6659a747e4fSDavid du Colombier 	mkqid(&qid, d, 1);
6669a747e4fSDavid du Colombier 	switch(f->mode & 7){
6679a747e4fSDavid du Colombier 
6689a747e4fSDavid du Colombier 	case OREAD:
6699a747e4fSDavid du Colombier 		if(iaccess(file, d, DREAD) && !wok)
6709a747e4fSDavid du Colombier 			goto badaccess;
6719a747e4fSDavid du Colombier 		fmod = FREAD;
6729a747e4fSDavid du Colombier 		break;
6739a747e4fSDavid du Colombier 
6749a747e4fSDavid du Colombier 	case OWRITE:
6759a747e4fSDavid du Colombier 		if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
6769a747e4fSDavid du Colombier 			goto badaccess;
6779a747e4fSDavid du Colombier 		if(ro){
6789a747e4fSDavid du Colombier 			error = Eronly;
6799a747e4fSDavid du Colombier 			goto out;
6809a747e4fSDavid du Colombier 		}
6819a747e4fSDavid du Colombier 		fmod = FWRITE;
6829a747e4fSDavid du Colombier 		break;
6839a747e4fSDavid du Colombier 
6849a747e4fSDavid du Colombier 	case ORDWR:
6859a747e4fSDavid du Colombier 		if((d->mode & DDIR)
6869a747e4fSDavid du Colombier 		|| (iaccess(file, d, DREAD) && !wok)
6879a747e4fSDavid du Colombier 		|| (iaccess(file, d, DWRITE) && !wok))
6889a747e4fSDavid du Colombier 			goto badaccess;
6899a747e4fSDavid du Colombier 		if(ro){
6909a747e4fSDavid du Colombier 			error = Eronly;
6919a747e4fSDavid du Colombier 			goto out;
6929a747e4fSDavid du Colombier 		}
6939a747e4fSDavid du Colombier 		fmod = FREAD+FWRITE;
6949a747e4fSDavid du Colombier 		break;
6959a747e4fSDavid du Colombier 
6969a747e4fSDavid du Colombier 	case OEXEC:
6979a747e4fSDavid du Colombier 		if((d->mode & DDIR) || (iaccess(file, d, DEXEC) && !wok))
6989a747e4fSDavid du Colombier 			goto badaccess;
6999a747e4fSDavid du Colombier 		fmod = FREAD;
7009a747e4fSDavid du Colombier 		break;
7019a747e4fSDavid du Colombier 
7029a747e4fSDavid du Colombier 	default:
7039a747e4fSDavid du Colombier 		error = Emode;
7049a747e4fSDavid du Colombier 		goto out;
7059a747e4fSDavid du Colombier 	}
7069a747e4fSDavid du Colombier 	if(f->mode & OTRUNC){
7079a747e4fSDavid du Colombier 		if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
7089a747e4fSDavid du Colombier 			goto badaccess;
7099a747e4fSDavid du Colombier 		if(ro){
7109a747e4fSDavid du Colombier 			error = Eronly;
7119a747e4fSDavid du Colombier 			goto out;
7129a747e4fSDavid du Colombier 		}
7139a747e4fSDavid du Colombier 	}
7149a747e4fSDavid du Colombier 	t = 0;
7159a747e4fSDavid du Colombier 	if(d->mode & DLOCK){
7169a747e4fSDavid du Colombier 		if((t = tlocked(p, d)) == nil){
7179a747e4fSDavid du Colombier 			error = Elocked;
7189a747e4fSDavid du Colombier 			goto out;
7199a747e4fSDavid du Colombier 		}
7209a747e4fSDavid du Colombier 	}
7219a747e4fSDavid du Colombier 	if(f->mode & ORCLOSE)
7229a747e4fSDavid du Colombier 		fmod |= FREMOV;
7239a747e4fSDavid du Colombier 	file->open = fmod;
7249a747e4fSDavid du Colombier 	if((f->mode & OTRUNC) && !(d->mode & DAPND)){
7259a747e4fSDavid du Colombier 		dtrunc(p, d);
7269a747e4fSDavid du Colombier 		qid.vers = d->qid.version;
7279a747e4fSDavid du Colombier 	}
7289a747e4fSDavid du Colombier 	r->qid = qid;
7299a747e4fSDavid du Colombier 	file->tlock = t;
7309a747e4fSDavid du Colombier 	if(t != nil)
7319a747e4fSDavid du Colombier 		t->file = file;
7329a747e4fSDavid du Colombier 	file->lastra = 1;
7339a747e4fSDavid du Colombier 	goto out;
7349a747e4fSDavid du Colombier 
7359a747e4fSDavid du Colombier badaccess:
7369a747e4fSDavid du Colombier 	error = Eaccess;
7379a747e4fSDavid du Colombier 	file->open = 0;
7389a747e4fSDavid du Colombier 
7399a747e4fSDavid du Colombier out:
7409a747e4fSDavid du Colombier 	if(p != nil)
7419a747e4fSDavid du Colombier 		putbuf(p);
7429a747e4fSDavid du Colombier 	if(file != nil)
7439a747e4fSDavid du Colombier 		qunlock(file);
7449a747e4fSDavid du Colombier 
7459a747e4fSDavid du Colombier 	r->iounit = chan->msize-IOHDRSZ;
7469a747e4fSDavid du Colombier 
7479a747e4fSDavid du Colombier 	return error;
7489a747e4fSDavid du Colombier }
7499a747e4fSDavid du Colombier 
7509a747e4fSDavid du Colombier static int
dir9p2(Dir * dir,Dentry * dentry,void * strs)7519a747e4fSDavid du Colombier dir9p2(Dir* dir, Dentry* dentry, void* strs)
7529a747e4fSDavid du Colombier {
7539a747e4fSDavid du Colombier 	char *op, *p;
7549a747e4fSDavid du Colombier 
7559a747e4fSDavid du Colombier 	memset(dir, 0, sizeof(Dir));
7569a747e4fSDavid du Colombier 	mkqid(&dir->qid, dentry, 1);
7579a747e4fSDavid du Colombier 	dir->mode = (dir->qid.type<<24)|(dentry->mode & 0777);
7589a747e4fSDavid du Colombier 	dir->atime = dentry->atime;
7599a747e4fSDavid du Colombier 	dir->mtime = dentry->mtime;
7609a747e4fSDavid du Colombier 	dir->length = dentry->size;
7619a747e4fSDavid du Colombier 
7629a747e4fSDavid du Colombier 	op = p = strs;
7639a747e4fSDavid du Colombier 	dir->name = p;
7649a747e4fSDavid du Colombier 	p += sprint(p, "%s", dentry->name)+1;
7659a747e4fSDavid du Colombier 
7669a747e4fSDavid du Colombier 	dir->uid = p;
7679a747e4fSDavid du Colombier 	uidtostr(p, dentry->uid);
7689a747e4fSDavid du Colombier 	p += strlen(p)+1;
7699a747e4fSDavid du Colombier 
7709a747e4fSDavid du Colombier 	dir->gid = p;
7719a747e4fSDavid du Colombier 	uidtostr(p, dentry->gid);
7729a747e4fSDavid du Colombier 	p += strlen(p)+1;
7739a747e4fSDavid du Colombier 
7749a747e4fSDavid du Colombier 	dir->muid = p;
7759a747e4fSDavid du Colombier 	strcpy(p, "");
7769a747e4fSDavid du Colombier 	p += strlen(p)+1;
7779a747e4fSDavid du Colombier 
7789a747e4fSDavid du Colombier 	return p-op;
7799a747e4fSDavid du Colombier }
7809a747e4fSDavid du Colombier 
7819a747e4fSDavid du Colombier static int
checkname9p2(char * name)7829a747e4fSDavid du Colombier checkname9p2(char* name)
7839a747e4fSDavid du Colombier {
7849a747e4fSDavid du Colombier 	char *p;
7859a747e4fSDavid du Colombier 
7869a747e4fSDavid du Colombier 	/*
7879a747e4fSDavid du Colombier 	 * Return length of string if valid, 0 if not.
7889a747e4fSDavid du Colombier 	 */
7899a747e4fSDavid du Colombier 	if(name == nil)
7909a747e4fSDavid du Colombier 		return 0;
7919a747e4fSDavid du Colombier 
7929a747e4fSDavid du Colombier 	for(p = name; *p != 0; p++){
7939a747e4fSDavid du Colombier 		if((*p & 0xFF) <= 040)
7949a747e4fSDavid du Colombier 			return 0;
7959a747e4fSDavid du Colombier 	}
7969a747e4fSDavid du Colombier 
7979a747e4fSDavid du Colombier 	return p-name;
7989a747e4fSDavid du Colombier }
7999a747e4fSDavid du Colombier 
8009a747e4fSDavid du Colombier static int
fscreate(Chan * chan,Fcall * f,Fcall * r)8019a747e4fSDavid du Colombier fscreate(Chan* chan, Fcall* f, Fcall* r)
8029a747e4fSDavid du Colombier {
8039a747e4fSDavid du Colombier 	Iobuf *p, *p1;
8049a747e4fSDavid du Colombier 	Dentry *d, *d1;
8059a747e4fSDavid du Colombier 	File *file;
8069a747e4fSDavid du Colombier 	int error, slot, slot1, fmod, wok, l;
8079a747e4fSDavid du Colombier 	long addr, addr1, path;
8089a747e4fSDavid du Colombier 	Tlock *t;
8099a747e4fSDavid du Colombier 	Wpath *w;
8109a747e4fSDavid du Colombier 
8119a747e4fSDavid du Colombier 	wok = 0;
8129a747e4fSDavid du Colombier 	p = nil;
8139a747e4fSDavid du Colombier 
8149a747e4fSDavid du Colombier 	if(chan == cons.chan || writeallow)
8159a747e4fSDavid du Colombier 		wok = 1;
8169a747e4fSDavid du Colombier 
8179a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil){
8189a747e4fSDavid du Colombier 		error = Efid;
8199a747e4fSDavid du Colombier 		goto out;
8209a747e4fSDavid du Colombier 	}
8215d459b5aSDavid du Colombier 	if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
8229a747e4fSDavid du Colombier 		error = Eronly;
8239a747e4fSDavid du Colombier 		goto out;
8249a747e4fSDavid du Colombier 	}
8259a747e4fSDavid du Colombier 
8269a747e4fSDavid du Colombier 	p = getbuf(file->fs->dev, file->addr, Bread);
8279a747e4fSDavid du Colombier 	if(p == nil || checktag(p, Tdir, QPNONE)){
8289a747e4fSDavid du Colombier 		error = Ealloc;
8299a747e4fSDavid du Colombier 		goto out;
8309a747e4fSDavid du Colombier 	}
8319a747e4fSDavid du Colombier 	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
8329a747e4fSDavid du Colombier 		error = Ealloc;
8339a747e4fSDavid du Colombier 		goto out;
8349a747e4fSDavid du Colombier 	}
8359a747e4fSDavid du Colombier 	if(error = mkqidcmp(&file->qid, d))
8369a747e4fSDavid du Colombier 		goto out;
8379a747e4fSDavid du Colombier 	if(!(d->mode & DDIR)){
8389a747e4fSDavid du Colombier 		error = Edir2;
8399a747e4fSDavid du Colombier 		goto out;
8409a747e4fSDavid du Colombier 	}
8419a747e4fSDavid du Colombier 	if(iaccess(file, d, DWRITE) && !wok) {
8429a747e4fSDavid du Colombier 		error = Eaccess;
8439a747e4fSDavid du Colombier 		goto out;
8449a747e4fSDavid du Colombier 	}
8459a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
8469a747e4fSDavid du Colombier 
8479a747e4fSDavid du Colombier 	/*
8489a747e4fSDavid du Colombier 	 * Check the name is valid and will fit in an old
8499a747e4fSDavid du Colombier 	 * directory entry.
8509a747e4fSDavid du Colombier 	 */
8519a747e4fSDavid du Colombier 	if((l = checkname9p2(f->name)) == 0){
8529a747e4fSDavid du Colombier 		error = Ename;
8539a747e4fSDavid du Colombier 		goto out;
8549a747e4fSDavid du Colombier 	}
8559a747e4fSDavid du Colombier 	if(l+1 > NAMELEN){
8569a747e4fSDavid du Colombier 		error = Etoolong;
8579a747e4fSDavid du Colombier 		goto out;
8589a747e4fSDavid du Colombier 	}
8599a747e4fSDavid du Colombier 	if(strcmp(f->name, ".") == 0 || strcmp(f->name, "..") == 0){
8609a747e4fSDavid du Colombier 		error = Edot;
8619a747e4fSDavid du Colombier 		goto out;
8629a747e4fSDavid du Colombier 	}
8639a747e4fSDavid du Colombier 
8649a747e4fSDavid du Colombier 	addr1 = 0;
8659a747e4fSDavid du Colombier 	slot1 = 0;	/* set */
8669a747e4fSDavid du Colombier 	for(addr = 0; ; addr++){
8679a747e4fSDavid du Colombier 		if((p1 = dnodebuf(p, d, addr, 0)) == nil){
8689a747e4fSDavid du Colombier 			if(addr1 != 0)
8699a747e4fSDavid du Colombier 				break;
8709a747e4fSDavid du Colombier 			p1 = dnodebuf(p, d, addr, Tdir);
8719a747e4fSDavid du Colombier 		}
8729a747e4fSDavid du Colombier 		if(p1 == nil){
8739a747e4fSDavid du Colombier 			error = Efull;
8749a747e4fSDavid du Colombier 			goto out;
8759a747e4fSDavid du Colombier 		}
8769a747e4fSDavid du Colombier 		if(checktag(p1, Tdir, d->qid.path)){
8779a747e4fSDavid du Colombier 			putbuf(p1);
8789a747e4fSDavid du Colombier 			goto phase;
8799a747e4fSDavid du Colombier 		}
8809a747e4fSDavid du Colombier 		for(slot = 0; slot < DIRPERBUF; slot++){
8819a747e4fSDavid du Colombier 			d1 = getdir(p1, slot);
8829a747e4fSDavid du Colombier 			if(!(d1->mode & DALLOC)){
8839a747e4fSDavid du Colombier 				if(addr1 == 0){
8849a747e4fSDavid du Colombier 					addr1 = p1->addr;
8859a747e4fSDavid du Colombier 					slot1 = slot + addr*DIRPERBUF;
8869a747e4fSDavid du Colombier 				}
8879a747e4fSDavid du Colombier 				continue;
8889a747e4fSDavid du Colombier 			}
8899a747e4fSDavid du Colombier 			if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){
8909a747e4fSDavid du Colombier 				putbuf(p1);
8919a747e4fSDavid du Colombier 				error = Eexist;
8929a747e4fSDavid du Colombier 				goto out;
8939a747e4fSDavid du Colombier 			}
8949a747e4fSDavid du Colombier 		}
8959a747e4fSDavid du Colombier 		putbuf(p1);
8969a747e4fSDavid du Colombier 	}
8979a747e4fSDavid du Colombier 
8989a747e4fSDavid du Colombier 	switch(f->mode & 7){
8999a747e4fSDavid du Colombier 	case OEXEC:
9009a747e4fSDavid du Colombier 	case OREAD:		/* seems only useful to make directories */
9019a747e4fSDavid du Colombier 		fmod = FREAD;
9029a747e4fSDavid du Colombier 		break;
9039a747e4fSDavid du Colombier 
9049a747e4fSDavid du Colombier 	case OWRITE:
9059a747e4fSDavid du Colombier 		fmod = FWRITE;
9069a747e4fSDavid du Colombier 		break;
9079a747e4fSDavid du Colombier 
9089a747e4fSDavid du Colombier 	case ORDWR:
9099a747e4fSDavid du Colombier 		fmod = FREAD+FWRITE;
9109a747e4fSDavid du Colombier 		break;
9119a747e4fSDavid du Colombier 
9129a747e4fSDavid du Colombier 	default:
9139a747e4fSDavid du Colombier 		error = Emode;
9149a747e4fSDavid du Colombier 		goto out;
9159a747e4fSDavid du Colombier 	}
9169a747e4fSDavid du Colombier 	if(f->perm & PDIR)
9179a747e4fSDavid du Colombier 		if((f->mode & OTRUNC) || (f->perm & PAPND) || (fmod & FWRITE))
9189a747e4fSDavid du Colombier 			goto badaccess;
9199a747e4fSDavid du Colombier 	/*
9209a747e4fSDavid du Colombier 	 * do it
9219a747e4fSDavid du Colombier 	 */
9229a747e4fSDavid du Colombier 	path = qidpathgen(&file->fs->dev);
9239a747e4fSDavid du Colombier 	if((p1 = getbuf(file->fs->dev, addr1, Bread|Bimm|Bmod)) == nil)
9249a747e4fSDavid du Colombier 		goto phase;
9259a747e4fSDavid du Colombier 	d1 = getdir(p1, slot1);
9269a747e4fSDavid du Colombier 	if(d1 == nil || checktag(p1, Tdir, d->qid.path)) {
9279a747e4fSDavid du Colombier 		putbuf(p1);
9289a747e4fSDavid du Colombier 		goto phase;
9299a747e4fSDavid du Colombier 	}
9309a747e4fSDavid du Colombier 	if(d1->mode & DALLOC){
9319a747e4fSDavid du Colombier 		putbuf(p1);
9329a747e4fSDavid du Colombier 		goto phase;
9339a747e4fSDavid du Colombier 	}
9349a747e4fSDavid du Colombier 
9359a747e4fSDavid du Colombier 	strncpy(d1->name, f->name, sizeof(d1->name));
9369a747e4fSDavid du Colombier 	if(chan == cons.chan){
9379a747e4fSDavid du Colombier 		d1->uid = cons.uid;
9389a747e4fSDavid du Colombier 		d1->gid = cons.gid;
9399a747e4fSDavid du Colombier 	}
9409a747e4fSDavid du Colombier 	else{
9419a747e4fSDavid du Colombier 		d1->uid = file->uid;
9429a747e4fSDavid du Colombier 		d1->gid = d->gid;
9439a747e4fSDavid du Colombier 		f->perm &= d->mode | ~0666;
9449a747e4fSDavid du Colombier 		if(f->perm & PDIR)
9459a747e4fSDavid du Colombier 			f->perm &= d->mode | ~0777;
9469a747e4fSDavid du Colombier 	}
9479a747e4fSDavid du Colombier 	d1->qid.path = path;
9489a747e4fSDavid du Colombier 	d1->qid.version = 0;
9499a747e4fSDavid du Colombier 	d1->mode = DALLOC | (f->perm & 0777);
9509a747e4fSDavid du Colombier 	if(f->perm & PDIR) {
9519a747e4fSDavid du Colombier 		d1->mode |= DDIR;
9529a747e4fSDavid du Colombier 		d1->qid.path |= QPDIR;
9539a747e4fSDavid du Colombier 	}
9549a747e4fSDavid du Colombier 	if(f->perm & PAPND)
9559a747e4fSDavid du Colombier 		d1->mode |= DAPND;
9569a747e4fSDavid du Colombier 	t = nil;
9579a747e4fSDavid du Colombier 	if(f->perm & PLOCK){
9589a747e4fSDavid du Colombier 		d1->mode |= DLOCK;
9599a747e4fSDavid du Colombier 		t = tlocked(p1, d1);
9609a747e4fSDavid du Colombier 		/* if nil, out of tlock structures */
9619a747e4fSDavid du Colombier 	}
9629a747e4fSDavid du Colombier 	accessdir(p1, d1, FWRITE);
9639a747e4fSDavid du Colombier 	mkqid(&r->qid, d1, 0);
9649a747e4fSDavid du Colombier 	putbuf(p1);
9659a747e4fSDavid du Colombier 	accessdir(p, d, FWRITE);
9669a747e4fSDavid du Colombier 
9679a747e4fSDavid du Colombier 	/*
9689a747e4fSDavid du Colombier 	 * do a walk to new directory entry
9699a747e4fSDavid du Colombier 	 */
9709a747e4fSDavid du Colombier 	if((w = newwp()) == nil){
9719a747e4fSDavid du Colombier 		error = Ewalk;
9729a747e4fSDavid du Colombier 		goto out;
9739a747e4fSDavid du Colombier 	}
9749a747e4fSDavid du Colombier 	w->addr = file->addr;
9759a747e4fSDavid du Colombier 	w->slot = file->slot;
9769a747e4fSDavid du Colombier 	w->up = file->wpath;
9779a747e4fSDavid du Colombier 	file->wpath = w;
9789a747e4fSDavid du Colombier 	file->qid = r->qid;
9799a747e4fSDavid du Colombier 	file->tlock = t;
9809a747e4fSDavid du Colombier 	if(t != nil)
9819a747e4fSDavid du Colombier 		t->file = file;
9829a747e4fSDavid du Colombier 	file->lastra = 1;
9839a747e4fSDavid du Colombier 	if(f->mode & ORCLOSE)
9849a747e4fSDavid du Colombier 		fmod |= FREMOV;
9859a747e4fSDavid du Colombier 	file->open = fmod;
9869a747e4fSDavid du Colombier 	file->addr = addr1;
9879a747e4fSDavid du Colombier 	file->slot = slot1;
9889a747e4fSDavid du Colombier 	goto out;
9899a747e4fSDavid du Colombier 
9909a747e4fSDavid du Colombier badaccess:
9919a747e4fSDavid du Colombier 	error = Eaccess;
9929a747e4fSDavid du Colombier 	goto out;
9939a747e4fSDavid du Colombier 
9949a747e4fSDavid du Colombier phase:
9959a747e4fSDavid du Colombier 	error = Ephase;
9969a747e4fSDavid du Colombier 
9979a747e4fSDavid du Colombier out:
9989a747e4fSDavid du Colombier 	if(p != nil)
9999a747e4fSDavid du Colombier 		putbuf(p);
10009a747e4fSDavid du Colombier 	if(file != nil)
10019a747e4fSDavid du Colombier 		qunlock(file);
10029a747e4fSDavid du Colombier 
10039a747e4fSDavid du Colombier 	r->iounit = chan->msize-IOHDRSZ;
10049a747e4fSDavid du Colombier 
10059a747e4fSDavid du Colombier 	return error;
10069a747e4fSDavid du Colombier }
10079a747e4fSDavid du Colombier 
10089a747e4fSDavid du Colombier static int
fsread(Chan * chan,Fcall * f,Fcall * r)10099a747e4fSDavid du Colombier fsread(Chan* chan, Fcall* f, Fcall* r)
10109a747e4fSDavid du Colombier {
10119a747e4fSDavid du Colombier 	uchar *data;
10129a747e4fSDavid du Colombier 	Iobuf *p, *p1;
10139a747e4fSDavid du Colombier 	File *file;
10149a747e4fSDavid du Colombier 	Dentry *d, *d1;
10159a747e4fSDavid du Colombier 	Tlock *t;
10169a747e4fSDavid du Colombier 	long addr, offset, start, tim;
10179a747e4fSDavid du Colombier 	int error, iounit, nread, count, n, o, slot;
10189a747e4fSDavid du Colombier 	Dir dir;
10199a747e4fSDavid du Colombier 	char strdata[28*10];
10209a747e4fSDavid du Colombier 
10219a747e4fSDavid du Colombier 	p = nil;
10229a747e4fSDavid du Colombier 	data = (uchar*)r->data;
10239a747e4fSDavid du Colombier 	count = f->count;
10249a747e4fSDavid du Colombier 	offset = f->offset;
10259a747e4fSDavid du Colombier 	nread = 0;
10269a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil){
10279a747e4fSDavid du Colombier 		error = Efid;
10289a747e4fSDavid du Colombier 		goto out;
10299a747e4fSDavid du Colombier 	}
10309a747e4fSDavid du Colombier 	if(file->qid.type & QTAUTH){
1031b7b24591SDavid du Colombier 		nread = authread(file, data, count);
10329a747e4fSDavid du Colombier 		if(nread < 0)
10339a747e4fSDavid du Colombier 			error = Esystem;
1034b7b24591SDavid du Colombier 		else
1035b7b24591SDavid du Colombier 			error = 0;
10369a747e4fSDavid du Colombier 		goto out;
10379a747e4fSDavid du Colombier 	}
10389a747e4fSDavid du Colombier 	if(!(file->open & FREAD)){
10399a747e4fSDavid du Colombier 		error = Eopen;
10409a747e4fSDavid du Colombier 		goto out;
10419a747e4fSDavid du Colombier 	}
10429a747e4fSDavid du Colombier 	iounit = chan->msize-IOHDRSZ;
10439a747e4fSDavid du Colombier 	if(count < 0 || count > iounit){
10449a747e4fSDavid du Colombier 		error = Ecount;
10459a747e4fSDavid du Colombier 		goto out;
10469a747e4fSDavid du Colombier 	}
10479a747e4fSDavid du Colombier 	if(offset < 0){
10489a747e4fSDavid du Colombier 		error = Eoffset;
10499a747e4fSDavid du Colombier 		goto out;
10509a747e4fSDavid du Colombier 	}
10519a747e4fSDavid du Colombier 	p = getbuf(file->fs->dev, file->addr, Bread);
10529a747e4fSDavid du Colombier 	if(p == nil || checktag(p, Tdir, QPNONE)){
10539a747e4fSDavid du Colombier 		error = Ealloc;
10549a747e4fSDavid du Colombier 		goto out;
10559a747e4fSDavid du Colombier 	}
10569a747e4fSDavid du Colombier 	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
10579a747e4fSDavid du Colombier 		error = Ealloc;
10589a747e4fSDavid du Colombier 		goto out;
10599a747e4fSDavid du Colombier 	}
10609a747e4fSDavid du Colombier 	if(error = mkqidcmp(&file->qid, d))
10619a747e4fSDavid du Colombier 		goto out;
10629a747e4fSDavid du Colombier 	if(t = file->tlock){
10639a747e4fSDavid du Colombier 		tim = time(0);
10649a747e4fSDavid du Colombier 		if(t->time < tim || t->file != file){
10659a747e4fSDavid du Colombier 			error = Ebroken;
10669a747e4fSDavid du Colombier 			goto out;
10679a747e4fSDavid du Colombier 		}
10689a747e4fSDavid du Colombier 		/* renew the lock */
10699a747e4fSDavid du Colombier 		t->time = tim + TLOCK;
10709a747e4fSDavid du Colombier 	}
10719a747e4fSDavid du Colombier 	accessdir(p, d, FREAD);
10729a747e4fSDavid du Colombier 	if(d->mode & DDIR)
10739a747e4fSDavid du Colombier 		goto dread;
10749a747e4fSDavid du Colombier 	if(offset+count > d->size)
10759a747e4fSDavid du Colombier 		count = d->size - offset;
10769a747e4fSDavid du Colombier 	while(count > 0){
10779a747e4fSDavid du Colombier 		if(p == nil){
10789a747e4fSDavid du Colombier 			p = getbuf(file->fs->dev, file->addr, Bread);
10799a747e4fSDavid du Colombier 			if(p == nil || checktag(p, Tdir, QPNONE)){
10809a747e4fSDavid du Colombier 				error = Ealloc;
10819a747e4fSDavid du Colombier 				goto out;
10829a747e4fSDavid du Colombier 			}
10839a747e4fSDavid du Colombier 			if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
10849a747e4fSDavid du Colombier 				error = Ealloc;
10859a747e4fSDavid du Colombier 				goto out;
10869a747e4fSDavid du Colombier 			}
10879a747e4fSDavid du Colombier 		}
10889a747e4fSDavid du Colombier 		addr = offset / BUFSIZE;
10899a747e4fSDavid du Colombier 		o = offset % BUFSIZE;
10909a747e4fSDavid du Colombier 		n = BUFSIZE - o;
10919a747e4fSDavid du Colombier 		if(n > count)
10929a747e4fSDavid du Colombier 			n = count;
10939a747e4fSDavid du Colombier 		p1 = dnodebuf1(p, d, addr, 0);
10949a747e4fSDavid du Colombier 		p = nil;
10959a747e4fSDavid du Colombier 		if(p1 != nil){
10969a747e4fSDavid du Colombier 			if(checktag(p1, Tfile, QPNONE)){
10979a747e4fSDavid du Colombier 				error = Ephase;
10989a747e4fSDavid du Colombier 				putbuf(p1);
10999a747e4fSDavid du Colombier 				goto out;
11009a747e4fSDavid du Colombier 			}
11019a747e4fSDavid du Colombier 			memmove(data+nread, p1->iobuf+o, n);
11029a747e4fSDavid du Colombier 			putbuf(p1);
11039a747e4fSDavid du Colombier 		}
11049a747e4fSDavid du Colombier 		else
11059a747e4fSDavid du Colombier 			memset(data+nread, 0, n);
11069a747e4fSDavid du Colombier 		count -= n;
11079a747e4fSDavid du Colombier 		nread += n;
11089a747e4fSDavid du Colombier 		offset += n;
11099a747e4fSDavid du Colombier 	}
11109a747e4fSDavid du Colombier 	goto out;
11119a747e4fSDavid du Colombier 
11129a747e4fSDavid du Colombier dread:
11139a747e4fSDavid du Colombier 	/*
11149a747e4fSDavid du Colombier 	 * Pick up where we left off last time if nothing has changed,
11159a747e4fSDavid du Colombier 	 * otherwise must scan from the beginning.
11169a747e4fSDavid du Colombier 	 */
11179a747e4fSDavid du Colombier 	if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){
11189a747e4fSDavid du Colombier 		addr = file->dslot/DIRPERBUF;
11199a747e4fSDavid du Colombier 		slot = file->dslot%DIRPERBUF;
11209a747e4fSDavid du Colombier 		start = offset;
11219a747e4fSDavid du Colombier 	}
11229a747e4fSDavid du Colombier 	else{
11239a747e4fSDavid du Colombier 		addr = 0;
11249a747e4fSDavid du Colombier 		slot = 0;
11259a747e4fSDavid du Colombier 		start = 0;
11269a747e4fSDavid du Colombier 	}
11279a747e4fSDavid du Colombier 
11289a747e4fSDavid du Colombier dread1:
11299a747e4fSDavid du Colombier 	if(p == nil){
11309a747e4fSDavid du Colombier 		/*
11319a747e4fSDavid du Colombier 		 * This is just a check to ensure the entry hasn't
11329a747e4fSDavid du Colombier 		 * gone away during the read of each directory block.
11339a747e4fSDavid du Colombier 		 */
11349a747e4fSDavid du Colombier 		p = getbuf(file->fs->dev, file->addr, Bread);
11359a747e4fSDavid du Colombier 		if(p == nil || checktag(p, Tdir, QPNONE)){
11369a747e4fSDavid du Colombier 			error = Ealloc;
11379a747e4fSDavid du Colombier 			goto out1;
11389a747e4fSDavid du Colombier 		}
11399a747e4fSDavid du Colombier 		if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
11409a747e4fSDavid du Colombier 			error = Ealloc;
11419a747e4fSDavid du Colombier 			goto out1;
11429a747e4fSDavid du Colombier 		}
11439a747e4fSDavid du Colombier 	}
11449a747e4fSDavid du Colombier 	p1 = dnodebuf1(p, d, addr, 0);
11459a747e4fSDavid du Colombier 	p = nil;
11469a747e4fSDavid du Colombier 	if(p1 == nil)
11479a747e4fSDavid du Colombier 		goto out1;
11489a747e4fSDavid du Colombier 	if(checktag(p1, Tdir, QPNONE)){
11499a747e4fSDavid du Colombier 		error = Ephase;
11509a747e4fSDavid du Colombier 		putbuf(p1);
11519a747e4fSDavid du Colombier 		goto out1;
11529a747e4fSDavid du Colombier 	}
11539a747e4fSDavid du Colombier 
11549a747e4fSDavid du Colombier 	for(; slot < DIRPERBUF; slot++){
11559a747e4fSDavid du Colombier 		d1 = getdir(p1, slot);
11569a747e4fSDavid du Colombier 		if(!(d1->mode & DALLOC))
11579a747e4fSDavid du Colombier 			continue;
11589a747e4fSDavid du Colombier 		dir9p2(&dir, d1, strdata);
11599a747e4fSDavid du Colombier 		if((n = convD2M(&dir, data+nread, iounit - nread)) <= BIT16SZ){
11609a747e4fSDavid du Colombier 			putbuf(p1);
11619a747e4fSDavid du Colombier 			goto out1;
11629a747e4fSDavid du Colombier 		}
11639a747e4fSDavid du Colombier 		start += n;
11649a747e4fSDavid du Colombier 		if(start < offset)
11659a747e4fSDavid du Colombier 			continue;
11669a747e4fSDavid du Colombier 		if(count < n){
11679a747e4fSDavid du Colombier 			putbuf(p1);
11689a747e4fSDavid du Colombier 			goto out1;
11699a747e4fSDavid du Colombier 		}
11709a747e4fSDavid du Colombier 		count -= n;
11719a747e4fSDavid du Colombier 		nread += n;
11729a747e4fSDavid du Colombier 		offset += n;
11739a747e4fSDavid du Colombier 	}
11749a747e4fSDavid du Colombier 	putbuf(p1);
11759a747e4fSDavid du Colombier 	slot = 0;
11769a747e4fSDavid du Colombier 	addr++;
11779a747e4fSDavid du Colombier 	goto dread1;
11789a747e4fSDavid du Colombier 
11799a747e4fSDavid du Colombier out1:
11809a747e4fSDavid du Colombier 	if(error == 0){
11819a747e4fSDavid du Colombier 		file->doffset = offset;
11829a747e4fSDavid du Colombier 		file->dvers = file->qid.vers;
11839a747e4fSDavid du Colombier 		file->dslot = slot+DIRPERBUF*addr;
11849a747e4fSDavid du Colombier 	}
11859a747e4fSDavid du Colombier 
11869a747e4fSDavid du Colombier out:
11879a747e4fSDavid du Colombier 	/*
11889a747e4fSDavid du Colombier 	 * Do we need this any more?
11899a747e4fSDavid du Colombier 	count = f->count - nread;
11909a747e4fSDavid du Colombier 	if(count > 0)
11919a747e4fSDavid du Colombier 		memset(data+nread, 0, count);
11929a747e4fSDavid du Colombier 	 */
11939a747e4fSDavid du Colombier 	if(p != nil)
11949a747e4fSDavid du Colombier 		putbuf(p);
11959a747e4fSDavid du Colombier 	if(file != nil)
11969a747e4fSDavid du Colombier 		qunlock(file);
11979a747e4fSDavid du Colombier 	r->count = nread;
11989a747e4fSDavid du Colombier 	r->data = (char*)data;
11999a747e4fSDavid du Colombier 
12009a747e4fSDavid du Colombier 	return error;
12019a747e4fSDavid du Colombier }
12029a747e4fSDavid du Colombier 
12039a747e4fSDavid du Colombier static int
fswrite(Chan * chan,Fcall * f,Fcall * r)12049a747e4fSDavid du Colombier fswrite(Chan* chan, Fcall* f, Fcall* r)
12059a747e4fSDavid du Colombier {
12069a747e4fSDavid du Colombier 	Iobuf *p, *p1;
12079a747e4fSDavid du Colombier 	Dentry *d;
12089a747e4fSDavid du Colombier 	File *file;
12099a747e4fSDavid du Colombier 	Tlock *t;
12109a747e4fSDavid du Colombier 	long offset, addr, tim, qpath;
12119a747e4fSDavid du Colombier 	int count, error, nwrite, o, n;
12129a747e4fSDavid du Colombier 
12139a747e4fSDavid du Colombier 	offset = f->offset;
12149a747e4fSDavid du Colombier 	count = f->count;
12159a747e4fSDavid du Colombier 
12169a747e4fSDavid du Colombier 	nwrite = 0;
12179a747e4fSDavid du Colombier 	p = nil;
12189a747e4fSDavid du Colombier 
12199a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil){
12209a747e4fSDavid du Colombier 		error = Efid;
12219a747e4fSDavid du Colombier 		goto out;
12229a747e4fSDavid du Colombier 	}
12239a747e4fSDavid du Colombier 	if(file->qid.type & QTAUTH){
1224b7b24591SDavid du Colombier 		nwrite = authwrite(file, (uchar*)f->data, count);
12259a747e4fSDavid du Colombier 		if(nwrite < 0)
12269a747e4fSDavid du Colombier 			error = Esystem;
1227b7b24591SDavid du Colombier 		else
1228b7b24591SDavid du Colombier 			error = 0;
12299a747e4fSDavid du Colombier 		goto out;
12309a747e4fSDavid du Colombier 	}
12319a747e4fSDavid du Colombier 	if(!(file->open & FWRITE)){
12329a747e4fSDavid du Colombier 		error = Eopen;
12339a747e4fSDavid du Colombier 		goto out;
12349a747e4fSDavid du Colombier 	}
12355d459b5aSDavid du Colombier 	if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
12369a747e4fSDavid du Colombier 		error = Eronly;
12379a747e4fSDavid du Colombier 		goto out;
12389a747e4fSDavid du Colombier 	}
12399a747e4fSDavid du Colombier 	if(count < 0 || count > chan->msize-IOHDRSZ){
12409a747e4fSDavid du Colombier 		error = Ecount;
12419a747e4fSDavid du Colombier 		goto out;
12429a747e4fSDavid du Colombier 	}
12439a747e4fSDavid du Colombier 	if(offset < 0) {
12449a747e4fSDavid du Colombier 		error = Eoffset;
12459a747e4fSDavid du Colombier 		goto out;
12469a747e4fSDavid du Colombier 	}
12479a747e4fSDavid du Colombier 	if((p = getbuf(file->fs->dev, file->addr, Bread|Bmod)) == nil){
12489a747e4fSDavid du Colombier 		error = Ealloc;
12499a747e4fSDavid du Colombier 		goto out;
12509a747e4fSDavid du Colombier 	}
12519a747e4fSDavid du Colombier 	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
12529a747e4fSDavid du Colombier 		error = Ealloc;
12539a747e4fSDavid du Colombier 		goto out;
12549a747e4fSDavid du Colombier 	}
12559a747e4fSDavid du Colombier 	if(error = mkqidcmp(&file->qid, d))
12569a747e4fSDavid du Colombier 		goto out;
12579a747e4fSDavid du Colombier 	if(t = file->tlock) {
12589a747e4fSDavid du Colombier 		tim = time(0);
12599a747e4fSDavid du Colombier 		if(t->time < tim || t->file != file){
12609a747e4fSDavid du Colombier 			error = Ebroken;
12619a747e4fSDavid du Colombier 			goto out;
12629a747e4fSDavid du Colombier 		}
12639a747e4fSDavid du Colombier 		/* renew the lock */
12649a747e4fSDavid du Colombier 		t->time = tim + TLOCK;
12659a747e4fSDavid du Colombier 	}
12669a747e4fSDavid du Colombier 	accessdir(p, d, FWRITE);
12679a747e4fSDavid du Colombier 	if(d->mode & DAPND)
12689a747e4fSDavid du Colombier 		offset = d->size;
12699a747e4fSDavid du Colombier 	if(offset+count > d->size)
12709a747e4fSDavid du Colombier 		d->size = offset+count;
12719a747e4fSDavid du Colombier 	while(count > 0){
12729a747e4fSDavid du Colombier 		if(p == nil){
12739a747e4fSDavid du Colombier 			p = getbuf(file->fs->dev, file->addr, Bread|Bmod);
12749a747e4fSDavid du Colombier 			if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
12759a747e4fSDavid du Colombier 				error = Ealloc;
12769a747e4fSDavid du Colombier 				goto out;
12779a747e4fSDavid du Colombier 			}
12789a747e4fSDavid du Colombier 		}
12799a747e4fSDavid du Colombier 		addr = offset / BUFSIZE;
12809a747e4fSDavid du Colombier 		o = offset % BUFSIZE;
12819a747e4fSDavid du Colombier 		n = BUFSIZE - o;
12829a747e4fSDavid du Colombier 		if(n > count)
12839a747e4fSDavid du Colombier 			n = count;
12849a747e4fSDavid du Colombier 		qpath = d->qid.path;
12859a747e4fSDavid du Colombier 		p1 = dnodebuf1(p, d, addr, Tfile);
12869a747e4fSDavid du Colombier 		p = nil;
12879a747e4fSDavid du Colombier 		if(p1 == nil) {
12889a747e4fSDavid du Colombier 			error = Efull;
12899a747e4fSDavid du Colombier 			goto out;
12909a747e4fSDavid du Colombier 		}
12919a747e4fSDavid du Colombier 		if(checktag(p1, Tfile, qpath)){
12929a747e4fSDavid du Colombier 			putbuf(p1);
12939a747e4fSDavid du Colombier 			error = Ephase;
12949a747e4fSDavid du Colombier 			goto out;
12959a747e4fSDavid du Colombier 		}
12969a747e4fSDavid du Colombier 		memmove(p1->iobuf+o, f->data+nwrite, n);
12979a747e4fSDavid du Colombier 		p1->flags |= Bmod;
12989a747e4fSDavid du Colombier 		putbuf(p1);
12999a747e4fSDavid du Colombier 		count -= n;
13009a747e4fSDavid du Colombier 		nwrite += n;
13019a747e4fSDavid du Colombier 		offset += n;
13029a747e4fSDavid du Colombier 	}
13039a747e4fSDavid du Colombier 
13049a747e4fSDavid du Colombier out:
13059a747e4fSDavid du Colombier 	if(p != nil)
13069a747e4fSDavid du Colombier 		putbuf(p);
13079a747e4fSDavid du Colombier 	if(file != nil)
13089a747e4fSDavid du Colombier 		qunlock(file);
13099a747e4fSDavid du Colombier 	r->count = nwrite;
13109a747e4fSDavid du Colombier 
13119a747e4fSDavid du Colombier 	return error;
13129a747e4fSDavid du Colombier }
13139a747e4fSDavid du Colombier 
13149a747e4fSDavid du Colombier static int
_clunk(File * file,int remove,int wok)13159a747e4fSDavid du Colombier _clunk(File* file, int remove, int wok)
13169a747e4fSDavid du Colombier {
13179a747e4fSDavid du Colombier 	Tlock *t;
13189a747e4fSDavid du Colombier 	int error;
13199a747e4fSDavid du Colombier 
13209a747e4fSDavid du Colombier 	error = 0;
13219a747e4fSDavid du Colombier 	if(t = file->tlock){
13229a747e4fSDavid du Colombier 		if(t->file == file)
13239a747e4fSDavid du Colombier 			t->time = 0;		/* free the lock */
13249a747e4fSDavid du Colombier 		file->tlock = 0;
13259a747e4fSDavid du Colombier 	}
13269a747e4fSDavid du Colombier 	if(remove)
13279a747e4fSDavid du Colombier 		error = doremove(file, wok);
13289a747e4fSDavid du Colombier 	file->open = 0;
13299a747e4fSDavid du Colombier 	freewp(file->wpath);
13309a747e4fSDavid du Colombier 	freefp(file);
13319a747e4fSDavid du Colombier 	qunlock(file);
13329a747e4fSDavid du Colombier 
13339a747e4fSDavid du Colombier 	return error;
13349a747e4fSDavid du Colombier }
13359a747e4fSDavid du Colombier 
13369a747e4fSDavid du Colombier static int
fsclunk(Chan * chan,Fcall * f,Fcall *)13379a747e4fSDavid du Colombier fsclunk(Chan* chan, Fcall* f, Fcall*)
13389a747e4fSDavid du Colombier {
13399a747e4fSDavid du Colombier 	File *file;
13409a747e4fSDavid du Colombier 
13419a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil)
13429a747e4fSDavid du Colombier 		return Efid;
13439a747e4fSDavid du Colombier 
13449a747e4fSDavid du Colombier 	_clunk(file, file->open & FREMOV, 0);
13459a747e4fSDavid du Colombier 	return 0;
13469a747e4fSDavid du Colombier }
13479a747e4fSDavid du Colombier 
13489a747e4fSDavid du Colombier static int
fsremove(Chan * chan,Fcall * f,Fcall *)13499a747e4fSDavid du Colombier fsremove(Chan* chan, Fcall* f, Fcall*)
13509a747e4fSDavid du Colombier {
13519a747e4fSDavid du Colombier 	File *file;
13529a747e4fSDavid du Colombier 
13539a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil)
13549a747e4fSDavid du Colombier 		return Efid;
13559a747e4fSDavid du Colombier 
13569a747e4fSDavid du Colombier 	return _clunk(file, 1, chan == cons.chan);
13579a747e4fSDavid du Colombier }
13589a747e4fSDavid du Colombier 
13599a747e4fSDavid du Colombier static int
fsstat(Chan * chan,Fcall * f,Fcall * r,uchar * data)13609a747e4fSDavid du Colombier fsstat(Chan* chan, Fcall* f, Fcall* r, uchar* data)
13619a747e4fSDavid du Colombier {
13629a747e4fSDavid du Colombier 	Dir dir;
13639a747e4fSDavid du Colombier 	Iobuf *p;
13649a747e4fSDavid du Colombier 	Dentry *d;
13659a747e4fSDavid du Colombier 	File *file;
13669a747e4fSDavid du Colombier 	int error, len;
13679a747e4fSDavid du Colombier 
13689a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil)
13699a747e4fSDavid du Colombier 		return Efid;
13709a747e4fSDavid du Colombier 
13719a747e4fSDavid du Colombier 	p = getbuf(file->fs->dev, file->addr, Bread);
13729a747e4fSDavid du Colombier 	if(p == nil || checktag(p, Tdir, QPNONE)){
13739a747e4fSDavid du Colombier 		error = Edir1;
13749a747e4fSDavid du Colombier 		goto out;
13759a747e4fSDavid du Colombier 	}
13769a747e4fSDavid du Colombier 	if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
13779a747e4fSDavid du Colombier 		error = Ealloc;
13789a747e4fSDavid du Colombier 		goto out;
13799a747e4fSDavid du Colombier 	}
13809a747e4fSDavid du Colombier 	if(error = mkqidcmp(&file->qid, d))
13819a747e4fSDavid du Colombier 		goto out;
13829a747e4fSDavid du Colombier 
13839a747e4fSDavid du Colombier 	if(d->qid.path == QPROOT)	/* stat of root gives time */
13849a747e4fSDavid du Colombier 		d->atime = time(0);
13859a747e4fSDavid du Colombier 
13869a747e4fSDavid du Colombier 	len = dir9p2(&dir, d, data);
13879a747e4fSDavid du Colombier 	data += len;
13889a747e4fSDavid du Colombier 	if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)
13899a747e4fSDavid du Colombier 		error = Ersc;
13909a747e4fSDavid du Colombier 	else
13919a747e4fSDavid du Colombier 		r->stat = data;
13929a747e4fSDavid du Colombier 
13939a747e4fSDavid du Colombier out:
13949a747e4fSDavid du Colombier 	if(p != nil)
13959a747e4fSDavid du Colombier 		putbuf(p);
13969a747e4fSDavid du Colombier 	if(file != nil)
13979a747e4fSDavid du Colombier 		qunlock(file);
13989a747e4fSDavid du Colombier 
13999a747e4fSDavid du Colombier 	return error;
14009a747e4fSDavid du Colombier }
14019a747e4fSDavid du Colombier 
14029a747e4fSDavid du Colombier static int
fswstat(Chan * chan,Fcall * f,Fcall *,char * strs)14039a747e4fSDavid du Colombier fswstat(Chan* chan, Fcall* f, Fcall*, char *strs)
14049a747e4fSDavid du Colombier {
14059a747e4fSDavid du Colombier 	Iobuf *p, *p1;
14069a747e4fSDavid du Colombier 	Dentry *d, *d1, xd;
14079a747e4fSDavid du Colombier 	File *file;
14089a747e4fSDavid du Colombier 	int error, slot, uid, gid, l;
14099a747e4fSDavid du Colombier 	long addr;
14109a747e4fSDavid du Colombier 	Dir dir;
14119a747e4fSDavid du Colombier 	ulong mode;
14129a747e4fSDavid du Colombier 
14139a747e4fSDavid du Colombier 	p = p1 = nil;
14149a747e4fSDavid du Colombier 	d1 = nil;
14159a747e4fSDavid du Colombier 
14169a747e4fSDavid du Colombier 	if((file = filep(chan, f->fid, 0)) == nil){
14179a747e4fSDavid du Colombier 		error = Efid;
14189a747e4fSDavid du Colombier 		goto out;
14199a747e4fSDavid du Colombier 	}
14209a747e4fSDavid du Colombier 
14219a747e4fSDavid du Colombier 	/*
14229a747e4fSDavid du Colombier 	 * if user none,
14239a747e4fSDavid du Colombier 	 * can't do anything
14249a747e4fSDavid du Colombier 	 * unless allow.
14259a747e4fSDavid du Colombier 	 */
14269a747e4fSDavid du Colombier 	if(file->uid == 0 && !wstatallow){
14279a747e4fSDavid du Colombier 		error = Eaccess;
14289a747e4fSDavid du Colombier 		goto out;
14299a747e4fSDavid du Colombier 	}
14309a747e4fSDavid du Colombier 
14315d459b5aSDavid du Colombier 	if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
14329a747e4fSDavid du Colombier 		error = Eronly;
14339a747e4fSDavid du Colombier 		goto out;
14349a747e4fSDavid du Colombier 	}
14359a747e4fSDavid du Colombier 
14369a747e4fSDavid du Colombier 	/*
14379a747e4fSDavid du Colombier 	 * first get parent
14389a747e4fSDavid du Colombier 	 */
14399a747e4fSDavid du Colombier 	if(file->wpath){
14409a747e4fSDavid du Colombier 		p1 = getbuf(file->fs->dev, file->wpath->addr, Bread);
14419a747e4fSDavid du Colombier 		if(p1 == nil){
14429a747e4fSDavid du Colombier 			error = Ephase;
14439a747e4fSDavid du Colombier 			goto out;
14449a747e4fSDavid du Colombier 		}
14459a747e4fSDavid du Colombier 		d1 = getdir(p1, file->wpath->slot);
14469a747e4fSDavid du Colombier 		if(d1 == nil || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)){
14479a747e4fSDavid du Colombier 			error = Ephase;
14489a747e4fSDavid du Colombier 			goto out;
14499a747e4fSDavid du Colombier 		}
14509a747e4fSDavid du Colombier 	}
14519a747e4fSDavid du Colombier 
14529a747e4fSDavid du Colombier 	if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){
14539a747e4fSDavid du Colombier 		error = Ealloc;
14549a747e4fSDavid du Colombier 		goto out;
14559a747e4fSDavid du Colombier 	}
14569a747e4fSDavid du Colombier 	d = getdir(p, file->slot);
14579a747e4fSDavid du Colombier 	if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)){
14589a747e4fSDavid du Colombier 		error = Ealloc;
14599a747e4fSDavid du Colombier 		goto out;
14609a747e4fSDavid du Colombier 	}
14619a747e4fSDavid du Colombier 	if(error = mkqidcmp(&file->qid, d))
14629a747e4fSDavid du Colombier 		goto out;
14639a747e4fSDavid du Colombier 
14649a747e4fSDavid du Colombier 	/*
14659a747e4fSDavid du Colombier 	 * Convert the message and fix up
14669a747e4fSDavid du Colombier 	 * fields not to be changed.
14679a747e4fSDavid du Colombier 	 */
14689a747e4fSDavid du Colombier 	if(convM2D(f->stat, f->nstat, &dir, strs) == 0){
14699a747e4fSDavid du Colombier 		print("9p2: convM2D returns 0\n");
14709a747e4fSDavid du Colombier 		error = Econvert;
14719a747e4fSDavid du Colombier 		goto out;
14729a747e4fSDavid du Colombier 	}
14739a747e4fSDavid du Colombier 	if(dir.uid == nil || strlen(dir.uid) == 0)
14749a747e4fSDavid du Colombier 		uid = d->uid;
14759a747e4fSDavid du Colombier 	else
14769a747e4fSDavid du Colombier 		uid = strtouid(dir.uid);
14779a747e4fSDavid du Colombier 	if(dir.gid == nil || strlen(dir.gid) == 0)
14789a747e4fSDavid du Colombier 		gid = d->gid;
14799a747e4fSDavid du Colombier 	else
14809a747e4fSDavid du Colombier 		gid = strtouid(dir.gid);
14819a747e4fSDavid du Colombier 	if(dir.name == nil || strlen(dir.name) == 0)
14829a747e4fSDavid du Colombier 		dir.name = d->name;
14839a747e4fSDavid du Colombier 	else{
14849a747e4fSDavid du Colombier 		if((l = checkname9p2(dir.name)) == 0){
14859a747e4fSDavid du Colombier 			error = Ename;
14869a747e4fSDavid du Colombier 			goto out;
14879a747e4fSDavid du Colombier 		}
14889a747e4fSDavid du Colombier 		if(l > NAMELEN){
14899a747e4fSDavid du Colombier 			error = Etoolong;
14909a747e4fSDavid du Colombier 			goto out;
14919a747e4fSDavid du Colombier 		}
14929a747e4fSDavid du Colombier 	}
14939a747e4fSDavid du Colombier 
14949a747e4fSDavid du Colombier 	/*
14959a747e4fSDavid du Colombier 	 * Before doing sanity checks, find out what the
14969a747e4fSDavid du Colombier 	 * new 'mode' should be:
14979a747e4fSDavid du Colombier 	 * if 'type' and 'mode' are both defaults, take the
14989a747e4fSDavid du Colombier 	 * new mode from the old directory entry;
14999a747e4fSDavid du Colombier 	 * else if 'type' is the default, use the new mode entry;
15009a747e4fSDavid du Colombier 	 * else if 'mode' is the default, create the new mode from
15019a747e4fSDavid du Colombier 	 * 'type' or'ed with the old directory mode;
15029a747e4fSDavid du Colombier 	 * else neither are defaults, use the new mode but check
15039a747e4fSDavid du Colombier 	 * it agrees with 'type'.
15049a747e4fSDavid du Colombier 	 */
15059a747e4fSDavid du Colombier 	if(dir.qid.type == 0xFF && dir.mode == ~0){
15069a747e4fSDavid du Colombier 		dir.mode = d->mode & 0777;
15079a747e4fSDavid du Colombier 		if(d->mode & DLOCK)
15089a747e4fSDavid du Colombier 			dir.mode |= DMEXCL;
15099a747e4fSDavid du Colombier 		if(d->mode & DAPND)
15109a747e4fSDavid du Colombier 			dir.mode |= DMAPPEND;
15119a747e4fSDavid du Colombier 		if(d->mode & DDIR)
15129a747e4fSDavid du Colombier 			dir.mode |= DMDIR;
15139a747e4fSDavid du Colombier 	}
15149a747e4fSDavid du Colombier 	else if(dir.qid.type == 0xFF){
15159a747e4fSDavid du Colombier 		/* nothing to do */
15169a747e4fSDavid du Colombier 	}
15179a747e4fSDavid du Colombier 	else if(dir.mode == ~0)
15189a747e4fSDavid du Colombier 		dir.mode = (dir.qid.type<<24)|(d->mode & 0777);
15199a747e4fSDavid du Colombier 	else if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
15209a747e4fSDavid du Colombier 		error = Eqidmode;
15219a747e4fSDavid du Colombier 		goto out;
15229a747e4fSDavid du Colombier 	}
15239a747e4fSDavid du Colombier 
15249a747e4fSDavid du Colombier 	/*
15259a747e4fSDavid du Colombier 	 * Check for unknown type/mode bits
15269a747e4fSDavid du Colombier 	 * and an attempt to change the directory bit.
15279a747e4fSDavid du Colombier 	 */
15289a747e4fSDavid du Colombier 	if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){
15299a747e4fSDavid du Colombier 		error = Enotm;
15309a747e4fSDavid du Colombier 		goto out;
15319a747e4fSDavid du Colombier 	}
15329a747e4fSDavid du Colombier 	if(d->mode & DDIR)
15339a747e4fSDavid du Colombier 		mode = DMDIR;
15349a747e4fSDavid du Colombier 	else
15359a747e4fSDavid du Colombier 		mode = 0;
15369a747e4fSDavid du Colombier 	if((dir.mode^mode) & DMDIR){
15379a747e4fSDavid du Colombier 		error = Enotd;
15389a747e4fSDavid du Colombier 		goto out;
15399a747e4fSDavid du Colombier 	}
15409a747e4fSDavid du Colombier 
15419a747e4fSDavid du Colombier 	if(dir.mtime == ~0)
15429a747e4fSDavid du Colombier 		dir.mtime = d->mtime;
15439a747e4fSDavid du Colombier 	if(dir.length == ~0)
15449a747e4fSDavid du Colombier 		dir.length = d->size;
15459a747e4fSDavid du Colombier 
15469a747e4fSDavid du Colombier 	/*
15479a747e4fSDavid du Colombier 	 * Currently, can't change length.
15489a747e4fSDavid du Colombier 	 */
15499a747e4fSDavid du Colombier 	if(dir.length != d->size){
15509a747e4fSDavid du Colombier 		error = Enotl;
15519a747e4fSDavid du Colombier 		goto out;
15529a747e4fSDavid du Colombier 	}
15539a747e4fSDavid du Colombier 
15549a747e4fSDavid du Colombier 	/*
15559a747e4fSDavid du Colombier 	 * if chown,
15569a747e4fSDavid du Colombier 	 * must be god
15579a747e4fSDavid du Colombier 	 * wstatallow set to allow chown during boot
15589a747e4fSDavid du Colombier 	 */
15599a747e4fSDavid du Colombier 	if(uid != d->uid && !wstatallow) {
15609a747e4fSDavid du Colombier 		error = Enotu;
15619a747e4fSDavid du Colombier 		goto out;
15629a747e4fSDavid du Colombier 	}
15639a747e4fSDavid du Colombier 
15649a747e4fSDavid du Colombier 	/*
15659a747e4fSDavid du Colombier 	 * if chgroup,
15669a747e4fSDavid du Colombier 	 * must be either
15679a747e4fSDavid du Colombier 	 *	a) owner and in new group
15689a747e4fSDavid du Colombier 	 *	b) leader of both groups
15699a747e4fSDavid du Colombier 	 * wstatallow and writeallow are set to allow chgrp during boot
15709a747e4fSDavid du Colombier 	 */
15719a747e4fSDavid du Colombier 	while(gid != d->gid) {
15729a747e4fSDavid du Colombier 		if(wstatallow || writeallow)
15739a747e4fSDavid du Colombier 			break;
15749a747e4fSDavid du Colombier 		if(d->uid == file->uid && ingroup(file->uid, gid))
15759a747e4fSDavid du Colombier 			break;
15769a747e4fSDavid du Colombier 		if(leadgroup(file->uid, gid))
15779a747e4fSDavid du Colombier 			if(leadgroup(file->uid, d->gid))
15789a747e4fSDavid du Colombier 				break;
15799a747e4fSDavid du Colombier 		error = Enotg;
15809a747e4fSDavid du Colombier 		goto out;
15819a747e4fSDavid du Colombier 	}
15829a747e4fSDavid du Colombier 
15839a747e4fSDavid du Colombier 	/*
15849a747e4fSDavid du Colombier 	 * if rename,
15859a747e4fSDavid du Colombier 	 * must have write permission in parent
15869a747e4fSDavid du Colombier 	 */
15879a747e4fSDavid du Colombier 	while(strncmp(d->name, dir.name, sizeof(d->name)) != 0) {
15889a747e4fSDavid du Colombier 		if(checkname(dir.name) || d1 == nil) {
15899a747e4fSDavid du Colombier 			error = Ename;
15909a747e4fSDavid du Colombier 			goto out;
15919a747e4fSDavid du Colombier 		}
15929a747e4fSDavid du Colombier 		if(strcmp(dir.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
15939a747e4fSDavid du Colombier 			error = Ename;
15949a747e4fSDavid du Colombier 			goto out;
15959a747e4fSDavid du Colombier 		}
15969a747e4fSDavid du Colombier 
15979a747e4fSDavid du Colombier 		/*
15989a747e4fSDavid du Colombier 		 * drop entry to prevent lock, then
15999a747e4fSDavid du Colombier 		 * check that destination name is unique,
16009a747e4fSDavid du Colombier 		 */
16019a747e4fSDavid du Colombier 		putbuf(p);
16029a747e4fSDavid du Colombier 		for(addr = 0; ; addr++) {
16039a747e4fSDavid du Colombier 			if((p = dnodebuf(p1, d1, addr, 0)) == nil)
16049a747e4fSDavid du Colombier 				break;
16059a747e4fSDavid du Colombier 			if(checktag(p, Tdir, d1->qid.path)) {
16069a747e4fSDavid du Colombier 				putbuf(p);
16079a747e4fSDavid du Colombier 				continue;
16089a747e4fSDavid du Colombier 			}
16099a747e4fSDavid du Colombier 			for(slot = 0; slot < DIRPERBUF; slot++) {
16109a747e4fSDavid du Colombier 				d = getdir(p, slot);
16119a747e4fSDavid du Colombier 				if(!(d->mode & DALLOC))
16129a747e4fSDavid du Colombier 					continue;
16139a747e4fSDavid du Colombier 				if(strncmp(dir.name, d->name, sizeof(d->name)) == 0) {
16149a747e4fSDavid du Colombier 					error = Eexist;
16159a747e4fSDavid du Colombier 					goto out;
16169a747e4fSDavid du Colombier 				}
16179a747e4fSDavid du Colombier 			}
16189a747e4fSDavid du Colombier 			putbuf(p);
16199a747e4fSDavid du Colombier 		}
16209a747e4fSDavid du Colombier 
16219a747e4fSDavid du Colombier 		/*
16229a747e4fSDavid du Colombier 		 * reacquire entry
16239a747e4fSDavid du Colombier 		 */
16249a747e4fSDavid du Colombier 		if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){
16259a747e4fSDavid du Colombier 			error = Ephase;
16269a747e4fSDavid du Colombier 			goto out;
16279a747e4fSDavid du Colombier 		}
16289a747e4fSDavid du Colombier 		d = getdir(p, file->slot);
16299a747e4fSDavid du Colombier 		if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
16309a747e4fSDavid du Colombier 			error = Ephase;
16319a747e4fSDavid du Colombier 			goto out;
16329a747e4fSDavid du Colombier 		}
16339a747e4fSDavid du Colombier 
16349a747e4fSDavid du Colombier 		if(wstatallow || writeallow) /* set to allow rename during boot */
16359a747e4fSDavid du Colombier 			break;
16369a747e4fSDavid du Colombier 		if(d1 == nil || iaccess(file, d1, DWRITE)) {
16379a747e4fSDavid du Colombier 			error = Eaccess;
16389a747e4fSDavid du Colombier 			goto out;
16399a747e4fSDavid du Colombier 		}
16409a747e4fSDavid du Colombier 		break;
16419a747e4fSDavid du Colombier 	}
16429a747e4fSDavid du Colombier 
16439a747e4fSDavid du Colombier 	/*
16449a747e4fSDavid du Colombier 	 * if mode/time, either
16459a747e4fSDavid du Colombier 	 *	a) owner
16469a747e4fSDavid du Colombier 	 *	b) leader of either group
16479a747e4fSDavid du Colombier 	 */
16489a747e4fSDavid du Colombier 	mode = dir.mode & 0777;
16499a747e4fSDavid du Colombier 	if(dir.mode & DMAPPEND)
16509a747e4fSDavid du Colombier 		mode |= DAPND;
16519a747e4fSDavid du Colombier 	if(dir.mode & DMEXCL)
16529a747e4fSDavid du Colombier 		mode |= DLOCK;
16539a747e4fSDavid du Colombier 	while(d->mtime != dir.mtime || ((d->mode^mode) & (DAPND|DLOCK|0777))) {
16549a747e4fSDavid du Colombier 		if(wstatallow)			/* set to allow chmod during boot */
16559a747e4fSDavid du Colombier 			break;
16569a747e4fSDavid du Colombier 		if(d->uid == file->uid)
16579a747e4fSDavid du Colombier 			break;
16589a747e4fSDavid du Colombier 		if(leadgroup(file->uid, gid))
16599a747e4fSDavid du Colombier 			break;
16609a747e4fSDavid du Colombier 		if(leadgroup(file->uid, d->gid))
16619a747e4fSDavid du Colombier 			break;
16629a747e4fSDavid du Colombier 		error = Enotu;
16639a747e4fSDavid du Colombier 		goto out;
16649a747e4fSDavid du Colombier 	}
16659a747e4fSDavid du Colombier 	d->mtime = dir.mtime;
16669a747e4fSDavid du Colombier 	d->uid = uid;
16679a747e4fSDavid du Colombier 	d->gid = gid;
16689a747e4fSDavid du Colombier 	d->mode = (mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
16699a747e4fSDavid du Colombier 
16709a747e4fSDavid du Colombier 	strncpy(d->name, dir.name, sizeof(d->name));
1671*229d2d34SDavid du Colombier 	accessdir(p, d, FWSTAT);
16729a747e4fSDavid du Colombier 
16739a747e4fSDavid du Colombier out:
16749a747e4fSDavid du Colombier 	if(p != nil)
16759a747e4fSDavid du Colombier 		putbuf(p);
16769a747e4fSDavid du Colombier 	if(p1 != nil)
16779a747e4fSDavid du Colombier 		putbuf(p1);
16789a747e4fSDavid du Colombier 	if(file != nil)
16799a747e4fSDavid du Colombier 		qunlock(file);
16809a747e4fSDavid du Colombier 
16819a747e4fSDavid du Colombier 	return error;
16829a747e4fSDavid du Colombier }
16839a747e4fSDavid du Colombier 
16849a747e4fSDavid du Colombier static int
recv(Chan * c,uchar * buf,int n)16859a747e4fSDavid du Colombier recv(Chan *c, uchar *buf, int n)
16869a747e4fSDavid du Colombier {
16879a747e4fSDavid du Colombier 	int fd, m, len;
16889a747e4fSDavid du Colombier 
16899a747e4fSDavid du Colombier 	fd = c->chan;
16909a747e4fSDavid du Colombier 	/* read count */
16919a747e4fSDavid du Colombier 	qlock(&c->rlock);
16929a747e4fSDavid du Colombier 	m = readn(fd, buf, BIT32SZ);
16939a747e4fSDavid du Colombier 	if(m != BIT32SZ){
16949a747e4fSDavid du Colombier 		qunlock(&c->rlock);
16959a747e4fSDavid du Colombier 		if(m < 0){
16969a747e4fSDavid du Colombier 			print("readn(BIT32SZ) fails: %r\n");
16979a747e4fSDavid du Colombier 			return -1;
16989a747e4fSDavid du Colombier 		}
16999a747e4fSDavid du Colombier 		print("readn(BIT32SZ) returns %d: %r\n", m);
17009a747e4fSDavid du Colombier 		return 0;
17019a747e4fSDavid du Colombier 	}
17029a747e4fSDavid du Colombier 
17039a747e4fSDavid du Colombier 	len = GBIT32(buf);
17049a747e4fSDavid du Colombier 	if(len <= BIT32SZ || len > n){
17059a747e4fSDavid du Colombier 		print("recv bad length %d\n", len);
17069a747e4fSDavid du Colombier 		werrstr("bad length in 9P2000 message header");
17079a747e4fSDavid du Colombier 		qunlock(&c->rlock);
17089a747e4fSDavid du Colombier 		return -1;
17099a747e4fSDavid du Colombier 	}
17109a747e4fSDavid du Colombier 	len -= BIT32SZ;
17119a747e4fSDavid du Colombier 	m = readn(fd, buf+BIT32SZ, len);
17129a747e4fSDavid du Colombier 	qunlock(&c->rlock);
17139a747e4fSDavid du Colombier 	if(m < len){
17149a747e4fSDavid du Colombier 		print("recv wanted %d got %d\n", len, m);
17159a747e4fSDavid du Colombier 		return 0;
17169a747e4fSDavid du Colombier 	}
17179a747e4fSDavid du Colombier 	return BIT32SZ+m;
17189a747e4fSDavid du Colombier }
17199a747e4fSDavid du Colombier 
17209a747e4fSDavid du Colombier static void
send(Chan * c,uchar * buf,int n)17219a747e4fSDavid du Colombier send(Chan *c, uchar *buf, int n)
17229a747e4fSDavid du Colombier {
17239a747e4fSDavid du Colombier 	int fd, m;
17249a747e4fSDavid du Colombier 
17259a747e4fSDavid du Colombier 	fd = c->chan;
17269a747e4fSDavid du Colombier 	qlock(&c->wlock);
17279a747e4fSDavid du Colombier 	m = write(fd, buf, n);
17289a747e4fSDavid du Colombier 	qunlock(&c->wlock);
17299a747e4fSDavid du Colombier 	if(m == n)
17309a747e4fSDavid du Colombier 		return;
17319a747e4fSDavid du Colombier 	panic("write failed");
17329a747e4fSDavid du Colombier }
17339a747e4fSDavid du Colombier 
17349a747e4fSDavid du Colombier void
serve9p2(Chan * chan,uchar * ib,int nib)17359a747e4fSDavid du Colombier serve9p2(Chan *chan, uchar *ib, int nib)
17369a747e4fSDavid du Colombier {
17379a747e4fSDavid du Colombier 	uchar inbuf[MSIZE+IOHDRSZ], outbuf[MSIZE+IOHDRSZ];
17389a747e4fSDavid du Colombier 	Fcall f, r;
17399a747e4fSDavid du Colombier 	char ename[64];
17409a747e4fSDavid du Colombier 	int error, n, type;
17419a747e4fSDavid du Colombier 
17429a747e4fSDavid du Colombier 	chan->msize = MSIZE;
17439a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
17449a747e4fSDavid du Colombier 
17459a747e4fSDavid du Colombier 	for(;;){
17469a747e4fSDavid du Colombier 		if(nib){
17479a747e4fSDavid du Colombier 			memmove(inbuf, ib, nib);
17489a747e4fSDavid du Colombier 			n = nib;
17499a747e4fSDavid du Colombier 			nib = 0;
17509a747e4fSDavid du Colombier 		}else
17519a747e4fSDavid du Colombier 			n = recv(chan, inbuf, sizeof inbuf);
17529a747e4fSDavid du Colombier 		if(chat){
17539a747e4fSDavid du Colombier 			print("read msg %d (fd %d)\n", n, chan->chan);
17549a747e4fSDavid du Colombier 			if(n <= 0)
17559a747e4fSDavid du Colombier 				print("\terr: %r\n");
17569a747e4fSDavid du Colombier 		}
17579a747e4fSDavid du Colombier 		if(n == 0 && (chan == cons.srvchan || chan == cons.chan))
17589a747e4fSDavid du Colombier 			continue;
17599a747e4fSDavid du Colombier 		if(n <= 0)
17609a747e4fSDavid du Colombier 			break;
17619a747e4fSDavid du Colombier 		if(convM2S(inbuf, n, &f) != n){
17629a747e4fSDavid du Colombier 			print("9p2: cannot decode\n");
17639a747e4fSDavid du Colombier 			continue;
17649a747e4fSDavid du Colombier 		}
17659a747e4fSDavid du Colombier 
17669a747e4fSDavid du Colombier 		type = f.type;
17679a747e4fSDavid du Colombier 		if(type < Tversion || type >= Tmax || (type&1) || type == Terror){
17689a747e4fSDavid du Colombier 			print("9p2: bad message type %d\n", type);
17699a747e4fSDavid du Colombier 			continue;
17709a747e4fSDavid du Colombier 		}
17719a747e4fSDavid du Colombier 
17729a747e4fSDavid du Colombier 		if(CHAT(chan))
17739a747e4fSDavid du Colombier 			print("9p2: f %F\n", &f);
17749a747e4fSDavid du Colombier 
17759a747e4fSDavid du Colombier 		r.type = type+1;
17769a747e4fSDavid du Colombier 		r.tag = f.tag;
17779a747e4fSDavid du Colombier 		error = 0;
17789a747e4fSDavid du Colombier 
17799a747e4fSDavid du Colombier 		rlock(&mainlock);
17809a747e4fSDavid du Colombier 		rlock(&chan->reflock);
17819a747e4fSDavid du Colombier 		switch(type){
17829a747e4fSDavid du Colombier 		default:
17839a747e4fSDavid du Colombier 			r.type = Rerror;
17849a747e4fSDavid du Colombier 			snprint(ename, sizeof ename, "unknown message: %F", &f);
17859a747e4fSDavid du Colombier 			r.ename = ename;
17869a747e4fSDavid du Colombier 			break;
17879a747e4fSDavid du Colombier 		case Tversion:
17889a747e4fSDavid du Colombier 			error = fsversion(chan, &f, &r);
17899a747e4fSDavid du Colombier 			break;
17909a747e4fSDavid du Colombier 		case Tauth:
17919a747e4fSDavid du Colombier 			error = fsauth(chan, &f, &r);
17929a747e4fSDavid du Colombier 			break;
17939a747e4fSDavid du Colombier 		case Tattach:
17949a747e4fSDavid du Colombier 			error = fsattach(chan, &f, &r);
17959a747e4fSDavid du Colombier 			break;
17969a747e4fSDavid du Colombier 		case Tflush:
17979a747e4fSDavid du Colombier 			error = fsflush(chan, &f, &r);
17989a747e4fSDavid du Colombier 			break;
17999a747e4fSDavid du Colombier 		case Twalk:
18009a747e4fSDavid du Colombier 			error = fswalk(chan, &f, &r);
18019a747e4fSDavid du Colombier 			break;
18029a747e4fSDavid du Colombier 		case Topen:
18039a747e4fSDavid du Colombier 			error = fsopen(chan, &f, &r);
18049a747e4fSDavid du Colombier 			break;
18059a747e4fSDavid du Colombier 		case Tcreate:
18069a747e4fSDavid du Colombier 			error = fscreate(chan, &f, &r);
18079a747e4fSDavid du Colombier 			break;
18089a747e4fSDavid du Colombier 		case Tread:
18099a747e4fSDavid du Colombier 			r.data = (char*)inbuf;
18109a747e4fSDavid du Colombier 			error = fsread(chan, &f, &r);
18119a747e4fSDavid du Colombier 			break;
18129a747e4fSDavid du Colombier 		case Twrite:
18139a747e4fSDavid du Colombier 			error = fswrite(chan, &f, &r);
18149a747e4fSDavid du Colombier 			break;
18159a747e4fSDavid du Colombier 		case Tclunk:
18169a747e4fSDavid du Colombier 			error = fsclunk(chan, &f, &r);
18179a747e4fSDavid du Colombier 			break;
18189a747e4fSDavid du Colombier 		case Tremove:
18199a747e4fSDavid du Colombier 			error = fsremove(chan, &f, &r);
18209a747e4fSDavid du Colombier 			break;
18219a747e4fSDavid du Colombier 		case Tstat:
18229a747e4fSDavid du Colombier 			error = fsstat(chan, &f, &r, inbuf);
18239a747e4fSDavid du Colombier 			break;
18249a747e4fSDavid du Colombier 		case Twstat:
18259a747e4fSDavid du Colombier 			error = fswstat(chan, &f, &r, (char*)outbuf);
18269a747e4fSDavid du Colombier 			break;
18279a747e4fSDavid du Colombier 		}
18289a747e4fSDavid du Colombier 		runlock(&chan->reflock);
18299a747e4fSDavid du Colombier 		runlock(&mainlock);
18309a747e4fSDavid du Colombier 
18319a747e4fSDavid du Colombier 		if(error != 0){
18329a747e4fSDavid du Colombier 			r.type = Rerror;
18339a747e4fSDavid du Colombier 			if(error >= MAXERR){
18349a747e4fSDavid du Colombier 				snprint(ename, sizeof(ename), "error %d", error);
18359a747e4fSDavid du Colombier 				r.ename = ename;
18369a747e4fSDavid du Colombier 			}
18379a747e4fSDavid du Colombier 			else
18389a747e4fSDavid du Colombier 				r.ename = errstring[error];
18399a747e4fSDavid du Colombier 		}
18409a747e4fSDavid du Colombier 		if(CHAT(chan))
18419a747e4fSDavid du Colombier 			print("9p2: r %F\n", &r);
18429a747e4fSDavid du Colombier 
18439a747e4fSDavid du Colombier 		n = convS2M(&r, outbuf, sizeof outbuf);
18449a747e4fSDavid du Colombier 		if(n == 0){
18459a747e4fSDavid du Colombier 			type = r.type;
18469a747e4fSDavid du Colombier 			r.type = Rerror;
18479a747e4fSDavid du Colombier 			snprint(ename, sizeof(ename), "9p2: convS2M: type %d", type);
18489a747e4fSDavid du Colombier 			r.ename = ename;
18499a747e4fSDavid du Colombier 			print(ename);
18509a747e4fSDavid du Colombier 			n = convS2M(&r, outbuf, sizeof outbuf);
18519a747e4fSDavid du Colombier 			if(n == 0){
18529a747e4fSDavid du Colombier 				/*
18539a747e4fSDavid du Colombier 				 * What to do here, the failure notification failed?
18549a747e4fSDavid du Colombier 				 */
18559a747e4fSDavid du Colombier 				panic("can't write anything at all");
18569a747e4fSDavid du Colombier 			}
18579a747e4fSDavid du Colombier 		}
18589a747e4fSDavid du Colombier 		send(chan, outbuf, n);
18599a747e4fSDavid du Colombier 	}
18609a747e4fSDavid du Colombier 	fileinit(chan);
18619a747e4fSDavid du Colombier 	close(chan->chan);
18629a747e4fSDavid du Colombier 	if(chan == cons.srvchan || chan == cons.chan)
18639a747e4fSDavid du Colombier 		print("console chan read error");
18649a747e4fSDavid du Colombier }
1865b7b24591SDavid du Colombier 
1866