xref: /plan9/sys/src/lib9p/srv.c (revision 2ebbfa15057a80d5ffc355d10c2a61bb0ac12c16)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <auth.h>
47dd7cddfSDavid du Colombier #include <fcall.h>
57dd7cddfSDavid du Colombier #include <thread.h>
69a747e4fSDavid du Colombier #include <9p.h>
77dd7cddfSDavid du Colombier 
89a747e4fSDavid du Colombier static char Ebadattach[] = "unknown specifier in attach";
99a747e4fSDavid du Colombier static char Ebadoffset[] = "bad offset";
109a747e4fSDavid du Colombier static char Ebadcount[] = "bad count";
119a747e4fSDavid du Colombier static char Ebotch[] = "9P protocol botch";
129a747e4fSDavid du Colombier static char Ecreatenondir[] = "create in non-directory";
139a747e4fSDavid du Colombier static char Edupfid[] = "duplicate fid";
149a747e4fSDavid du Colombier static char Eduptag[] = "duplicate tag";
159a747e4fSDavid du Colombier static char Eisdir[] = "is a directory";
169a747e4fSDavid du Colombier static char Enocreate[] = "create prohibited";
179a747e4fSDavid du Colombier static char Enomem[] = "out of memory";
189a747e4fSDavid du Colombier static char Enoremove[] = "remove prohibited";
199a747e4fSDavid du Colombier static char Enostat[] = "stat prohibited";
209a747e4fSDavid du Colombier static char Enotfound[] = "file not found";
217dd7cddfSDavid du Colombier static char Enowrite[] = "write prohibited";
227dd7cddfSDavid du Colombier static char Enowstat[] = "wstat prohibited";
239a747e4fSDavid du Colombier static char Eperm[] = "permission denied";
249a747e4fSDavid du Colombier static char Eunknownfid[] = "unknown fid";
259a747e4fSDavid du Colombier static char Ebaddir[] = "bad directory in wstat";
269a747e4fSDavid du Colombier static char Ewalknodir[] = "walk in non-directory";
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier static void
297dd7cddfSDavid du Colombier setfcallerror(Fcall *f, char *err)
307dd7cddfSDavid du Colombier {
319a747e4fSDavid du Colombier 	f->ename = err;
327dd7cddfSDavid du Colombier 	f->type = Rerror;
337dd7cddfSDavid du Colombier }
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier static void
369a747e4fSDavid du Colombier changemsize(Srv *srv, int msize)
377dd7cddfSDavid du Colombier {
389a747e4fSDavid du Colombier 	if(srv->rbuf && srv->wbuf && srv->msize == msize)
399a747e4fSDavid du Colombier 		return;
409a747e4fSDavid du Colombier 	qlock(&srv->rlock);
419a747e4fSDavid du Colombier 	qlock(&srv->wlock);
429a747e4fSDavid du Colombier 	srv->msize = msize;
439a747e4fSDavid du Colombier 	free(srv->rbuf);
449a747e4fSDavid du Colombier 	free(srv->wbuf);
459a747e4fSDavid du Colombier 	srv->rbuf = emalloc9p(msize);
469a747e4fSDavid du Colombier 	srv->wbuf = emalloc9p(msize);
479a747e4fSDavid du Colombier 	qunlock(&srv->rlock);
489a747e4fSDavid du Colombier 	qunlock(&srv->wlock);
497dd7cddfSDavid du Colombier }
507dd7cddfSDavid du Colombier 
519a747e4fSDavid du Colombier static Req*
529a747e4fSDavid du Colombier getreq(Srv *s)
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier 	long n;
559a747e4fSDavid du Colombier 	uchar *buf;
567dd7cddfSDavid du Colombier 	Fcall f;
577dd7cddfSDavid du Colombier 	Req *r;
587dd7cddfSDavid du Colombier 
599a747e4fSDavid du Colombier 	qlock(&s->rlock);
609a747e4fSDavid du Colombier 	if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){
619a747e4fSDavid du Colombier 		qunlock(&s->rlock);
627dd7cddfSDavid du Colombier 		return nil;
639a747e4fSDavid du Colombier 	}
647dd7cddfSDavid du Colombier 
659a747e4fSDavid du Colombier 	buf = emalloc9p(n);
669a747e4fSDavid du Colombier 	memmove(buf, s->rbuf, n);
679a747e4fSDavid du Colombier 	qunlock(&s->rlock);
689a747e4fSDavid du Colombier 
699a747e4fSDavid du Colombier 	if(convM2S(buf, n, &f) != n){
707dd7cddfSDavid du Colombier 		free(buf);
717dd7cddfSDavid du Colombier 		return nil;
727dd7cddfSDavid du Colombier 	}
739a747e4fSDavid du Colombier 
749a747e4fSDavid du Colombier 	if((r=allocreq(s->rpool, f.tag)) == nil){	/* duplicate tag: cons up a fake Req */
759a747e4fSDavid du Colombier 		r = emalloc9p(sizeof *r);
767dd7cddfSDavid du Colombier 		incref(&r->ref);
777dd7cddfSDavid du Colombier 		r->tag = f.tag;
789a747e4fSDavid du Colombier 		r->ifcall = f;
797dd7cddfSDavid du Colombier 		r->error = Eduptag;
807dd7cddfSDavid du Colombier 		r->buf = buf;
817dd7cddfSDavid du Colombier 		r->responded = 0;
829a747e4fSDavid du Colombier 		r->type = 0;
839a747e4fSDavid du Colombier 		r->srv = s;
849a747e4fSDavid du Colombier 		r->pool = nil;
859a747e4fSDavid du Colombier if(chatty9p)
869a747e4fSDavid du Colombier 	fprint(2, "<-%d- %F: dup tag\n", s->infd, &f);
877dd7cddfSDavid du Colombier 		return r;
887dd7cddfSDavid du Colombier 	}
897dd7cddfSDavid du Colombier 
909a747e4fSDavid du Colombier 	r->srv = s;
917dd7cddfSDavid du Colombier 	r->responded = 0;
927dd7cddfSDavid du Colombier 	r->buf = buf;
939a747e4fSDavid du Colombier 	r->ifcall = f;
949a747e4fSDavid du Colombier 	memset(&r->ofcall, 0, sizeof r->ofcall);
959a747e4fSDavid du Colombier 	r->type = r->ifcall.type;
967dd7cddfSDavid du Colombier 
979a747e4fSDavid du Colombier if(chatty9p)
987dd7cddfSDavid du Colombier 	if(r->error)
999a747e4fSDavid du Colombier 		fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error);
1007dd7cddfSDavid du Colombier 	else
1019a747e4fSDavid du Colombier 		fprint(2, "<-%d- %F\n", s->infd, &r->ifcall);
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier 	return r;
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier 
1069a747e4fSDavid du Colombier static void
1079a747e4fSDavid du Colombier filewalk(Req *r)
1089a747e4fSDavid du Colombier {
1099a747e4fSDavid du Colombier 	int i;
1109a747e4fSDavid du Colombier 	File *f;
1117dd7cddfSDavid du Colombier 
1129a747e4fSDavid du Colombier 	f = r->fid->file;
1139a747e4fSDavid du Colombier 	assert(f != nil);
1149a747e4fSDavid du Colombier 
1159a747e4fSDavid du Colombier 	incref(f);
1169a747e4fSDavid du Colombier 	for(i=0; i<r->ifcall.nwname; i++)
1179a747e4fSDavid du Colombier 		if(f = walkfile(f, r->ifcall.wname[i]))
1189a747e4fSDavid du Colombier 			r->ofcall.wqid[i] = f->qid;
1199a747e4fSDavid du Colombier 		else
1209a747e4fSDavid du Colombier 			break;
1219a747e4fSDavid du Colombier 
1229a747e4fSDavid du Colombier 	r->ofcall.nwqid = i;
1239a747e4fSDavid du Colombier 	if(f){
1249a747e4fSDavid du Colombier 		r->newfid->file = f;
1259a747e4fSDavid du Colombier 		r->newfid->qid = r->newfid->file->qid;
1269a747e4fSDavid du Colombier 	}
1279a747e4fSDavid du Colombier 	respond(r, nil);
1289a747e4fSDavid du Colombier }
1299a747e4fSDavid du Colombier 
1307fd46167SDavid du Colombier void
1317fd46167SDavid du Colombier walkandclone(Req *r, char *(*walk1)(Fid*, char*, void*), char *(*clone)(Fid*, Fid*, void*), void *arg)
1329a747e4fSDavid du Colombier {
1339a747e4fSDavid du Colombier 	int i;
1349a747e4fSDavid du Colombier 	char *e;
1359a747e4fSDavid du Colombier 
1369a747e4fSDavid du Colombier 	if(r->fid == r->newfid && r->ifcall.nwname > 1){
1379a747e4fSDavid du Colombier 		respond(r, "lib9p: unused documented feature not implemented");
1389a747e4fSDavid du Colombier 		return;
1399a747e4fSDavid du Colombier 	}
1409a747e4fSDavid du Colombier 
1419a747e4fSDavid du Colombier 	if(r->fid != r->newfid){
1429a747e4fSDavid du Colombier 		r->newfid->qid = r->fid->qid;
1437fd46167SDavid du Colombier 		if(clone && (e = clone(r->fid, r->newfid, arg))){
1449a747e4fSDavid du Colombier 			respond(r, e);
1459a747e4fSDavid du Colombier 			return;
1469a747e4fSDavid du Colombier 		}
1479a747e4fSDavid du Colombier 	}
1489a747e4fSDavid du Colombier 
1499a747e4fSDavid du Colombier 	e = nil;
1509a747e4fSDavid du Colombier 	for(i=0; i<r->ifcall.nwname; i++){
1517fd46167SDavid du Colombier 		if(e = walk1(r->newfid, r->ifcall.wname[i], arg))
1529a747e4fSDavid du Colombier 			break;
1537fd46167SDavid du Colombier 		r->ofcall.wqid[i] = r->newfid->qid;
1549a747e4fSDavid du Colombier 	}
1559a747e4fSDavid du Colombier 
1569a747e4fSDavid du Colombier 	r->ofcall.nwqid = i;
1579a747e4fSDavid du Colombier 	if(e && i==0)
1589a747e4fSDavid du Colombier 		respond(r, e);
1599a747e4fSDavid du Colombier 	else
1609a747e4fSDavid du Colombier 		respond(r, nil);
1619a747e4fSDavid du Colombier }
1627dd7cddfSDavid du Colombier 
1637fd46167SDavid du Colombier static void
1647fd46167SDavid du Colombier sversion(Srv*, Req *r)
1657dd7cddfSDavid du Colombier {
1669a747e4fSDavid du Colombier 	if(strncmp(r->ifcall.version, "9P", 2) != 0){
1679a747e4fSDavid du Colombier 		r->ofcall.version = "unknown";
1689a747e4fSDavid du Colombier 		respond(r, nil);
1697fd46167SDavid du Colombier 		return;
1709a747e4fSDavid du Colombier 	}
1719a747e4fSDavid du Colombier 
1729a747e4fSDavid du Colombier 	r->ofcall.version = "9P2000";
1739a747e4fSDavid du Colombier 	r->ofcall.msize = r->ifcall.msize;
1747dd7cddfSDavid du Colombier 	respond(r, nil);
1757fd46167SDavid du Colombier }
1767fd46167SDavid du Colombier static void
1777fd46167SDavid du Colombier rversion(Req *r, char *error)
1787fd46167SDavid du Colombier {
1797fd46167SDavid du Colombier 	assert(error == nil);
1807fd46167SDavid du Colombier 	changemsize(r->srv, r->ofcall.msize);
1817fd46167SDavid du Colombier }
1827dd7cddfSDavid du Colombier 
1837fd46167SDavid du Colombier static void
1847fd46167SDavid du Colombier sauth(Srv *srv, Req *r)
1857fd46167SDavid du Colombier {
1867fd46167SDavid du Colombier 	char e[ERRMAX];
1877fd46167SDavid du Colombier 
1889a747e4fSDavid du Colombier 	if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){
1899a747e4fSDavid du Colombier 		respond(r, Edupfid);
1907fd46167SDavid du Colombier 		return;
1919a747e4fSDavid du Colombier 	}
1929a747e4fSDavid du Colombier 	if(srv->auth)
1939a747e4fSDavid du Colombier 		srv->auth(r);
1949a747e4fSDavid du Colombier 	else{
1959a747e4fSDavid du Colombier 		snprint(e, sizeof e, "%s: authentication not required", argv0);
1969a747e4fSDavid du Colombier 		respond(r, e);
1979a747e4fSDavid du Colombier 	}
1987fd46167SDavid du Colombier }
1997fd46167SDavid du Colombier static void
2007fd46167SDavid du Colombier rauth(Req *r, char *error)
2017fd46167SDavid du Colombier {
2027fd46167SDavid du Colombier 	if(error && r->afid)
2037fd46167SDavid du Colombier 		closefid(removefid(r->srv->fpool, r->afid->fid));
2047fd46167SDavid du Colombier }
2059a747e4fSDavid du Colombier 
2067fd46167SDavid du Colombier static void
2077fd46167SDavid du Colombier sattach(Srv *srv, Req *r)
2087fd46167SDavid du Colombier {
2099a747e4fSDavid du Colombier 	if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){
2109a747e4fSDavid du Colombier 		respond(r, Edupfid);
2117fd46167SDavid du Colombier 		return;
2129a747e4fSDavid du Colombier 	}
2139a747e4fSDavid du Colombier 	r->afid = nil;
2143ff48bf5SDavid du Colombier 	if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){
2159a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
2167fd46167SDavid du Colombier 		return;
2179a747e4fSDavid du Colombier 	}
2189a747e4fSDavid du Colombier 	r->fid->uid = estrdup9p(r->ifcall.uname);
2199a747e4fSDavid du Colombier 	if(srv->tree){
2209a747e4fSDavid du Colombier 		r->fid->file = srv->tree->root;
2219a747e4fSDavid du Colombier 		/* BUG? incref(r->fid->file) ??? */
2229a747e4fSDavid du Colombier 		r->ofcall.qid = r->fid->file->qid;
2239a747e4fSDavid du Colombier 		r->fid->qid = r->ofcall.qid;
2249a747e4fSDavid du Colombier 	}
2259a747e4fSDavid du Colombier 	if(srv->attach)
2269a747e4fSDavid du Colombier 		srv->attach(r);
2277dd7cddfSDavid du Colombier 	else
2287dd7cddfSDavid du Colombier 		respond(r, nil);
2297fd46167SDavid du Colombier 	return;
2307fd46167SDavid du Colombier }
2317fd46167SDavid du Colombier static void
2327fd46167SDavid du Colombier rattach(Req *r, char *error)
2337fd46167SDavid du Colombier {
2347fd46167SDavid du Colombier 	if(error && r->fid)
2357fd46167SDavid du Colombier 		closefid(removefid(r->srv->fpool, r->fid->fid));
2367fd46167SDavid du Colombier }
2377dd7cddfSDavid du Colombier 
2387fd46167SDavid du Colombier static void
2397fd46167SDavid du Colombier sflush(Srv *srv, Req *r)
2407fd46167SDavid du Colombier {
2419a747e4fSDavid du Colombier 	r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag);
2429a747e4fSDavid du Colombier 	if(r->oldreq == nil || r->oldreq == r)
2439a747e4fSDavid du Colombier 		respond(r, nil);
2449a747e4fSDavid du Colombier 	else if(srv->flush)
2459a747e4fSDavid du Colombier 		srv->flush(r);
2467dd7cddfSDavid du Colombier 	else
2477fd46167SDavid du Colombier 		respond(r, nil);
2487fd46167SDavid du Colombier }
2497fd46167SDavid du Colombier static int
2507fd46167SDavid du Colombier rflush(Req *r, char *error)
2517fd46167SDavid du Colombier {
2527fd46167SDavid du Colombier 	Req *or;
2537dd7cddfSDavid du Colombier 
2547fd46167SDavid du Colombier 	assert(error == nil);
2557fd46167SDavid du Colombier 	or = r->oldreq;
2567fd46167SDavid du Colombier 	if(or){
2577fd46167SDavid du Colombier 		qlock(&or->lk);
2587fd46167SDavid du Colombier 		if(or->responded == 0){
2597fd46167SDavid du Colombier 			or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0]));
2607fd46167SDavid du Colombier 			or->flush[or->nflush++] = r;
2617fd46167SDavid du Colombier 			qunlock(&or->lk);
2627fd46167SDavid du Colombier 			return -1;		/* delay response until or is responded */
2637fd46167SDavid du Colombier 		}
2647fd46167SDavid du Colombier 		qunlock(&or->lk);
2657fd46167SDavid du Colombier 		closereq(or);
2667fd46167SDavid du Colombier 	}
2677fd46167SDavid du Colombier 	r->oldreq = nil;
2687fd46167SDavid du Colombier 	return 0;
2697fd46167SDavid du Colombier }
2707fd46167SDavid du Colombier 
2717fd46167SDavid du Colombier static char*
2727fd46167SDavid du Colombier oldwalk1(Fid *fid, char *name, void *arg)
2737fd46167SDavid du Colombier {
2747fd46167SDavid du Colombier 	char *e;
2757fd46167SDavid du Colombier 	Qid qid;
2767fd46167SDavid du Colombier 	Srv *srv;
2777fd46167SDavid du Colombier 
2787fd46167SDavid du Colombier 	srv = arg;
2797fd46167SDavid du Colombier 	e = srv->walk1(fid, name, &qid);
2807fd46167SDavid du Colombier 	if(e)
2817fd46167SDavid du Colombier 		return e;
282*2ebbfa15SDavid du Colombier 	fid->qid = qid;
2837fd46167SDavid du Colombier 	return nil;
2847fd46167SDavid du Colombier }
2857fd46167SDavid du Colombier 
2867fd46167SDavid du Colombier static char*
2877fd46167SDavid du Colombier oldclone(Fid *fid, Fid *newfid, void *arg)
2887fd46167SDavid du Colombier {
2897fd46167SDavid du Colombier 	Srv *srv;
2907fd46167SDavid du Colombier 
2917fd46167SDavid du Colombier 	srv = arg;
2927fd46167SDavid du Colombier 	if(srv->clone == nil)
2937fd46167SDavid du Colombier 		return nil;
2947fd46167SDavid du Colombier 	return srv->clone(fid, newfid);
2957fd46167SDavid du Colombier }
2967fd46167SDavid du Colombier 
2977fd46167SDavid du Colombier static void
2987fd46167SDavid du Colombier swalk(Srv *srv, Req *r)
2997fd46167SDavid du Colombier {
3009a747e4fSDavid du Colombier 	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
3019a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
3027fd46167SDavid du Colombier 		return;
3037dd7cddfSDavid du Colombier 	}
3049a747e4fSDavid du Colombier 	if(r->fid->omode != -1){
3059a747e4fSDavid du Colombier 		respond(r, "cannot clone open fid");
3067fd46167SDavid du Colombier 		return;
3079a747e4fSDavid du Colombier 	}
3089a747e4fSDavid du Colombier 	if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){
3099a747e4fSDavid du Colombier 		respond(r, Ewalknodir);
3107fd46167SDavid du Colombier 		return;
3119a747e4fSDavid du Colombier 	}
3129a747e4fSDavid du Colombier 	if(r->ifcall.fid != r->ifcall.newfid){
3139a747e4fSDavid du Colombier 		if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){
3149a747e4fSDavid du Colombier 			respond(r, Edupfid);
3157fd46167SDavid du Colombier 			return;
3169a747e4fSDavid du Colombier 		}
3179a747e4fSDavid du Colombier 		r->newfid->uid = estrdup9p(r->fid->uid);
3189a747e4fSDavid du Colombier 	}else{
3199a747e4fSDavid du Colombier 		incref(&r->fid->ref);
3209a747e4fSDavid du Colombier 		r->newfid = r->fid;
3219a747e4fSDavid du Colombier 	}
3229a747e4fSDavid du Colombier 	if(r->fid->file){
3239a747e4fSDavid du Colombier 		filewalk(r);
3249a747e4fSDavid du Colombier 	}else if(srv->walk1)
3257fd46167SDavid du Colombier 		walkandclone(r, oldwalk1, oldclone, srv);
3269a747e4fSDavid du Colombier 	else if(srv->walk)
3279a747e4fSDavid du Colombier 		srv->walk(r);
3289a747e4fSDavid du Colombier 	else
3299a747e4fSDavid du Colombier 		sysfatal("no walk function, no file trees");
3307fd46167SDavid du Colombier }
3317fd46167SDavid du Colombier static void
3327fd46167SDavid du Colombier rwalk(Req *r, char *error)
3337fd46167SDavid du Colombier {
3347fd46167SDavid du Colombier 	if(error || r->ofcall.nwqid < r->ifcall.nwname){
3357fd46167SDavid du Colombier 		if(r->ifcall.fid != r->ifcall.newfid && r->newfid)
3367fd46167SDavid du Colombier 			closefid(removefid(r->srv->fpool, r->newfid->fid));
3377fd46167SDavid du Colombier 		if (r->ofcall.nwqid==0){
3387fd46167SDavid du Colombier 			if(error==nil && r->ifcall.nwname!=0)
3397fd46167SDavid du Colombier 				r->error = Enotfound;
3407fd46167SDavid du Colombier 		}else
3417fd46167SDavid du Colombier 			r->error = nil;	// No error on partial walks
3427fd46167SDavid du Colombier 	}else{
3437fd46167SDavid du Colombier 		if(r->ofcall.nwqid == 0){
3447fd46167SDavid du Colombier 			/* Just a clone */
3457fd46167SDavid du Colombier 			r->newfid->qid = r->fid->qid;
3467fd46167SDavid du Colombier 		}else{
3477fd46167SDavid du Colombier 			/* if file trees are in use, filewalk took care of the rest */
3487fd46167SDavid du Colombier 			r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1];
3497fd46167SDavid du Colombier 		}
3507fd46167SDavid du Colombier 	}
3517fd46167SDavid du Colombier }
3527dd7cddfSDavid du Colombier 
3537fd46167SDavid du Colombier static void
3547fd46167SDavid du Colombier sopen(Srv *srv, Req *r)
3557fd46167SDavid du Colombier {
3567fd46167SDavid du Colombier 	int p;
3577fd46167SDavid du Colombier 
3589a747e4fSDavid du Colombier 	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
3599a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
3607fd46167SDavid du Colombier 		return;
3619a747e4fSDavid du Colombier 	}
3627dd7cddfSDavid du Colombier 	if(r->fid->omode != -1){
3637dd7cddfSDavid du Colombier 		respond(r, Ebotch);
3647fd46167SDavid du Colombier 		return;
3657dd7cddfSDavid du Colombier 	}
3669a747e4fSDavid du Colombier 	if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){
3679a747e4fSDavid du Colombier 		respond(r, Eisdir);
3687fd46167SDavid du Colombier 		return;
3697dd7cddfSDavid du Colombier 	}
3709a747e4fSDavid du Colombier 	r->ofcall.qid = r->fid->qid;
3719a747e4fSDavid du Colombier 	switch(r->ifcall.mode&3){
3729a747e4fSDavid du Colombier 	default:
3739a747e4fSDavid du Colombier 		assert(0);
3749a747e4fSDavid du Colombier 	case OREAD:
3759a747e4fSDavid du Colombier 		p = AREAD;
3769a747e4fSDavid du Colombier 		break;
3779a747e4fSDavid du Colombier 	case OWRITE:
3789a747e4fSDavid du Colombier 		p = AWRITE;
3799a747e4fSDavid du Colombier 		break;
3809a747e4fSDavid du Colombier 	case ORDWR:
3819a747e4fSDavid du Colombier 		p = AREAD|AWRITE;
3829a747e4fSDavid du Colombier 		break;
3839a747e4fSDavid du Colombier 	case OEXEC:
3849a747e4fSDavid du Colombier 		p = AEXEC;
3859a747e4fSDavid du Colombier 		break;
3869a747e4fSDavid du Colombier 	}
3879a747e4fSDavid du Colombier 	if(r->ifcall.mode&OTRUNC)
3887dd7cddfSDavid du Colombier 		p |= AWRITE;
3899a747e4fSDavid du Colombier 	if((r->fid->qid.type&QTDIR) && p!=AREAD){
3909a747e4fSDavid du Colombier 		respond(r, Eperm);
3917fd46167SDavid du Colombier 		return;
3929a747e4fSDavid du Colombier 	}
3939a747e4fSDavid du Colombier 	if(r->fid->file){
3947dd7cddfSDavid du Colombier 		if(!hasperm(r->fid->file, r->fid->uid, p)){
3957dd7cddfSDavid du Colombier 			respond(r, Eperm);
3967fd46167SDavid du Colombier 			return;
3977dd7cddfSDavid du Colombier 		}
3989a747e4fSDavid du Colombier 	/* BUG RACE */
3999a747e4fSDavid du Colombier 		if((r->ifcall.mode&ORCLOSE)
4007dd7cddfSDavid du Colombier 		&& !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
4017dd7cddfSDavid du Colombier 			respond(r, Eperm);
4027fd46167SDavid du Colombier 			return;
4037dd7cddfSDavid du Colombier 		}
40480ee5cbfSDavid du Colombier 		r->ofcall.qid = r->fid->file->qid;
4059a747e4fSDavid du Colombier 		if((r->ofcall.qid.type&QTDIR)
4069a747e4fSDavid du Colombier 		&& (r->fid->rdir = opendirfile(r->fid->file)) == nil){
4079a747e4fSDavid du Colombier 			respond(r, "opendirfile failed");
4087fd46167SDavid du Colombier 			return;
4099a747e4fSDavid du Colombier 		}
4107dd7cddfSDavid du Colombier 	}
4117dd7cddfSDavid du Colombier 	if(srv->open)
4129a747e4fSDavid du Colombier 		srv->open(r);
4137dd7cddfSDavid du Colombier 	else
4147dd7cddfSDavid du Colombier 		respond(r, nil);
4157fd46167SDavid du Colombier }
4167fd46167SDavid du Colombier static void
4177fd46167SDavid du Colombier ropen(Req *r, char *error)
4187fd46167SDavid du Colombier {
4197fd46167SDavid du Colombier 	char errbuf[ERRMAX];
4207fd46167SDavid du Colombier 	if(error)
4217fd46167SDavid du Colombier 		return;
4227fd46167SDavid du Colombier 	if(chatty9p){
4237fd46167SDavid du Colombier 		snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode);
4247fd46167SDavid du Colombier 		write(2, errbuf, strlen(errbuf));
4257fd46167SDavid du Colombier 	}
4267fd46167SDavid du Colombier 	r->fid->omode = r->ifcall.mode;
4277fd46167SDavid du Colombier 	r->fid->qid = r->ofcall.qid;
4287fd46167SDavid du Colombier 	if(r->ofcall.qid.type&QTDIR)
4297fd46167SDavid du Colombier 		r->fid->diroffset = 0;
4307fd46167SDavid du Colombier }
4317dd7cddfSDavid du Colombier 
4327fd46167SDavid du Colombier static void
4337fd46167SDavid du Colombier screate(Srv *srv, Req *r)
4347fd46167SDavid du Colombier {
4359a747e4fSDavid du Colombier 	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil)
4369a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
4379a747e4fSDavid du Colombier 	else if(r->fid->omode != -1)
4389a747e4fSDavid du Colombier 		respond(r, Ebotch);
4399a747e4fSDavid du Colombier 	else if(!(r->fid->qid.type&QTDIR))
4409a747e4fSDavid du Colombier 		respond(r, Ecreatenondir);
4417dd7cddfSDavid du Colombier 	else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE))
4429a747e4fSDavid du Colombier 		respond(r, Eperm);
4439a747e4fSDavid du Colombier 	else if(srv->create)
4449a747e4fSDavid du Colombier 		srv->create(r);
4457dd7cddfSDavid du Colombier 	else
4469a747e4fSDavid du Colombier 		respond(r, Enocreate);
4477fd46167SDavid du Colombier }
4487fd46167SDavid du Colombier static void
4497fd46167SDavid du Colombier rcreate(Req *r, char *error)
4507fd46167SDavid du Colombier {
4517fd46167SDavid du Colombier 	if(error)
4527fd46167SDavid du Colombier 		return;
4537fd46167SDavid du Colombier 	r->fid->omode = r->ifcall.mode;
4547fd46167SDavid du Colombier 	r->fid->qid = r->ofcall.qid;
4557fd46167SDavid du Colombier }
4567dd7cddfSDavid du Colombier 
4577fd46167SDavid du Colombier static void
4587fd46167SDavid du Colombier sread(Srv *srv, Req *r)
4597fd46167SDavid du Colombier {
4607fd46167SDavid du Colombier 	int o;
4617fd46167SDavid du Colombier 
4629a747e4fSDavid du Colombier 	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
4639a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
4647fd46167SDavid du Colombier 		return;
4657dd7cddfSDavid du Colombier 	}
4669a747e4fSDavid du Colombier 	if(r->ifcall.count < 0){
4679a747e4fSDavid du Colombier 		respond(r, Ebotch);
4687fd46167SDavid du Colombier 		return;
4699a747e4fSDavid du Colombier 	}
4709a747e4fSDavid du Colombier 	if(r->ifcall.offset < 0
4719a747e4fSDavid du Colombier 	|| ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){
4729a747e4fSDavid du Colombier 		respond(r, Ebadoffset);
4737fd46167SDavid du Colombier 		return;
4749a747e4fSDavid du Colombier 	}
4759a747e4fSDavid du Colombier 
4769a747e4fSDavid du Colombier 	if(r->ifcall.count > srv->msize - IOHDRSZ)
4779a747e4fSDavid du Colombier 		r->ifcall.count = srv->msize - IOHDRSZ;
4787fd46167SDavid du Colombier 	r->rbuf = emalloc9p(r->ifcall.count);
4799a747e4fSDavid du Colombier 	r->ofcall.data = r->rbuf;
4809a747e4fSDavid du Colombier 	o = r->fid->omode & 3;
4819a747e4fSDavid du Colombier 	if(o != OREAD && o != ORDWR && o != OEXEC){
4829a747e4fSDavid du Colombier 		respond(r, Ebotch);
4837fd46167SDavid du Colombier 		return;
4849a747e4fSDavid du Colombier 	}
4859a747e4fSDavid du Colombier 	if((r->fid->qid.type&QTDIR) && r->fid->file){
4869a747e4fSDavid du Colombier 		r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count);
4879a747e4fSDavid du Colombier 		respond(r, nil);
4887fd46167SDavid du Colombier 		return;
4899a747e4fSDavid du Colombier 	}
4909a747e4fSDavid du Colombier 	if(srv->read)
4919a747e4fSDavid du Colombier 		srv->read(r);
4929a747e4fSDavid du Colombier 	else
4939a747e4fSDavid du Colombier 		respond(r, "no srv->read");
4947fd46167SDavid du Colombier }
4957fd46167SDavid du Colombier static void
4967fd46167SDavid du Colombier rread(Req *r, char *error)
4977fd46167SDavid du Colombier {
4987fd46167SDavid du Colombier 	if(error==nil && (r->fid->qid.type&QTDIR))
4997fd46167SDavid du Colombier 		r->fid->diroffset += r->ofcall.count;
5007fd46167SDavid du Colombier }
5017dd7cddfSDavid du Colombier 
5027fd46167SDavid du Colombier static void
5037fd46167SDavid du Colombier swrite(Srv *srv, Req *r)
5047fd46167SDavid du Colombier {
5057fd46167SDavid du Colombier 	int o;
5067fd46167SDavid du Colombier 	char e[ERRMAX];
5077fd46167SDavid du Colombier 
5089a747e4fSDavid du Colombier 	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
5099a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
5107fd46167SDavid du Colombier 		return;
5117dd7cddfSDavid du Colombier 	}
5129a747e4fSDavid du Colombier 	if(r->ifcall.count < 0){
5139a747e4fSDavid du Colombier 		respond(r, Ebotch);
5147fd46167SDavid du Colombier 		return;
5159a747e4fSDavid du Colombier 	}
5169a747e4fSDavid du Colombier 	if(r->ifcall.offset < 0){
5179a747e4fSDavid du Colombier 		respond(r, Ebotch);
5187fd46167SDavid du Colombier 		return;
5199a747e4fSDavid du Colombier 	}
5209a747e4fSDavid du Colombier 	if(r->ifcall.count > srv->msize - IOHDRSZ)
5219a747e4fSDavid du Colombier 		r->ifcall.count = srv->msize - IOHDRSZ;
5229a747e4fSDavid du Colombier 	o = r->fid->omode & 3;
5239a747e4fSDavid du Colombier 	if(o != OWRITE && o != ORDWR){
5249a747e4fSDavid du Colombier 		snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode);
5259a747e4fSDavid du Colombier 		respond(r, e);
5267fd46167SDavid du Colombier 		return;
5279a747e4fSDavid du Colombier 	}
5289a747e4fSDavid du Colombier 	if(srv->write)
5299a747e4fSDavid du Colombier 		srv->write(r);
5309a747e4fSDavid du Colombier 	else
5319a747e4fSDavid du Colombier 		respond(r, "no srv->write");
5327fd46167SDavid du Colombier }
5337fd46167SDavid du Colombier static void
5347fd46167SDavid du Colombier rwrite(Req *r, char *error)
5357fd46167SDavid du Colombier {
5367fd46167SDavid du Colombier 	if(error)
5377fd46167SDavid du Colombier 		return;
5387fd46167SDavid du Colombier 	if(r->fid->file)
5397fd46167SDavid du Colombier 		r->fid->file->qid.vers++;
5407fd46167SDavid du Colombier }
5417dd7cddfSDavid du Colombier 
5427fd46167SDavid du Colombier static void
5437fd46167SDavid du Colombier sclunk(Srv *srv, Req *r)
5447fd46167SDavid du Colombier {
5459a747e4fSDavid du Colombier 	if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil)
5469a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
5479a747e4fSDavid du Colombier 	else
5487dd7cddfSDavid du Colombier 		respond(r, nil);
5497fd46167SDavid du Colombier }
5507fd46167SDavid du Colombier static void
5517fd46167SDavid du Colombier rclunk(Req*, char*)
5527fd46167SDavid du Colombier {
5537fd46167SDavid du Colombier }
5547dd7cddfSDavid du Colombier 
5557fd46167SDavid du Colombier static void
5567fd46167SDavid du Colombier sremove(Srv *srv, Req *r)
5577fd46167SDavid du Colombier {
5589a747e4fSDavid du Colombier 	if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){
5599a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
5607fd46167SDavid du Colombier 		return;
5619a747e4fSDavid du Colombier 	}
5629a747e4fSDavid du Colombier 	/* BUG RACE */
5639a747e4fSDavid du Colombier 	if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
5647dd7cddfSDavid du Colombier 		respond(r, Eperm);
5657fd46167SDavid du Colombier 		return;
5667dd7cddfSDavid du Colombier 	}
5679a747e4fSDavid du Colombier 	if(srv->remove)
5689a747e4fSDavid du Colombier 		srv->remove(r);
5697dd7cddfSDavid du Colombier 	else
5709a747e4fSDavid du Colombier 		respond(r, r->fid->file ? nil : Enoremove);
5717fd46167SDavid du Colombier }
5727fd46167SDavid du Colombier static void
5737fd46167SDavid du Colombier rremove(Req *r, char *error, char *errbuf)
5747fd46167SDavid du Colombier {
5757fd46167SDavid du Colombier 	if(error)
5767fd46167SDavid du Colombier 		return;
5777fd46167SDavid du Colombier 	if(r->fid->file){
5787fd46167SDavid du Colombier 		if(removefile(r->fid->file) < 0){
5797fd46167SDavid du Colombier 			snprint(errbuf, ERRMAX, "remove %s: %r",
5807fd46167SDavid du Colombier 				r->fid->file->name);
5817fd46167SDavid du Colombier 			r->error = errbuf;
5827fd46167SDavid du Colombier 		}
5837fd46167SDavid du Colombier 		r->fid->file = nil;
5847fd46167SDavid du Colombier 	}
5857fd46167SDavid du Colombier }
5867dd7cddfSDavid du Colombier 
5877fd46167SDavid du Colombier static void
5887fd46167SDavid du Colombier sstat(Srv *srv, Req *r)
5897fd46167SDavid du Colombier {
5909a747e4fSDavid du Colombier 	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
5919a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
5927fd46167SDavid du Colombier 		return;
5937dd7cddfSDavid du Colombier 	}
5949a747e4fSDavid du Colombier 	if(r->fid->file){
5959a747e4fSDavid du Colombier 		r->d = r->fid->file->Dir;
5969a747e4fSDavid du Colombier 		if(r->d.name)
5979a747e4fSDavid du Colombier 			r->d.name = estrdup9p(r->d.name);
5989a747e4fSDavid du Colombier 		if(r->d.uid)
5999a747e4fSDavid du Colombier 			r->d.uid = estrdup9p(r->d.uid);
6009a747e4fSDavid du Colombier 		if(r->d.gid)
6019a747e4fSDavid du Colombier 			r->d.gid = estrdup9p(r->d.gid);
6029a747e4fSDavid du Colombier 		if(r->d.muid)
6039a747e4fSDavid du Colombier 			r->d.muid = estrdup9p(r->d.muid);
6049a747e4fSDavid du Colombier 	}
6057dd7cddfSDavid du Colombier 	if(srv->stat)
6069a747e4fSDavid du Colombier 		srv->stat(r);
6079a747e4fSDavid du Colombier 	else if(r->fid->file)
6087dd7cddfSDavid du Colombier 		respond(r, nil);
6099a747e4fSDavid du Colombier 	else
6109a747e4fSDavid du Colombier 		respond(r, Enostat);
6117fd46167SDavid du Colombier }
6127fd46167SDavid du Colombier static void
6137fd46167SDavid du Colombier rstat(Req *r, char *error)
6147fd46167SDavid du Colombier {
6157fd46167SDavid du Colombier 	int n;
6167fd46167SDavid du Colombier 	uchar *statbuf;
6177fd46167SDavid du Colombier 	uchar tmp[BIT16SZ];
6187dd7cddfSDavid du Colombier 
6197fd46167SDavid du Colombier 	if(error)
6207fd46167SDavid du Colombier 		return;
6217fd46167SDavid du Colombier 	if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){
6227fd46167SDavid du Colombier 		r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ";
6237fd46167SDavid du Colombier 		return;
6247fd46167SDavid du Colombier 	}
6257fd46167SDavid du Colombier 	n = GBIT16(tmp)+BIT16SZ;
6267fd46167SDavid du Colombier 	statbuf = emalloc9p(n);
6277fd46167SDavid du Colombier 	if(statbuf == nil){
6287fd46167SDavid du Colombier 		r->error = "out of memory";
6297fd46167SDavid du Colombier 		return;
6307fd46167SDavid du Colombier 	}
6317fd46167SDavid du Colombier 	r->ofcall.nstat = convD2M(&r->d, statbuf, n);
6327fd46167SDavid du Colombier 	r->ofcall.stat = statbuf;	/* freed in closereq */
6337fd46167SDavid du Colombier 	if(r->ofcall.nstat < 0){
6347fd46167SDavid du Colombier 		r->error = "convD2M fails";
6357fd46167SDavid du Colombier 		free(statbuf);
6367fd46167SDavid du Colombier 		return;
6377fd46167SDavid du Colombier 	}
6387fd46167SDavid du Colombier }
6397fd46167SDavid du Colombier 
6407fd46167SDavid du Colombier static void
6417fd46167SDavid du Colombier swstat(Srv *srv, Req *r)
6427fd46167SDavid du Colombier {
6437fd46167SDavid du Colombier 	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
6449a747e4fSDavid du Colombier 		respond(r, Eunknownfid);
6457fd46167SDavid du Colombier 		return;
6467fd46167SDavid du Colombier 	}
6477fd46167SDavid du Colombier 	if(srv->wstat == nil){
6489a747e4fSDavid du Colombier 		respond(r, Enowstat);
6497fd46167SDavid du Colombier 		return;
6507fd46167SDavid du Colombier 	}
6517fd46167SDavid du Colombier 	if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){
6527fd46167SDavid du Colombier 		respond(r, Ebaddir);
6537fd46167SDavid du Colombier 		return;
6547fd46167SDavid du Colombier 	}
6557fd46167SDavid du Colombier 	if((ushort)~r->d.type){
6567fd46167SDavid du Colombier 		respond(r, "wstat -- attempt to change type");
6577fd46167SDavid du Colombier 		return;
6587fd46167SDavid du Colombier 	}
6597fd46167SDavid du Colombier 	if((uint)~r->d.dev){
6607fd46167SDavid du Colombier 		respond(r, "wstat -- attempt to change dev");
6617fd46167SDavid du Colombier 		return;
6627fd46167SDavid du Colombier 	}
6637fd46167SDavid du Colombier 	if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){
6647fd46167SDavid du Colombier 		respond(r, "wstat -- attempt to change qid");
6657fd46167SDavid du Colombier 		return;
6667fd46167SDavid du Colombier 	}
6677fd46167SDavid du Colombier 	if(r->d.muid && r->d.muid[0]){
6687fd46167SDavid du Colombier 		respond(r, "wstat -- attempt to change muid");
6697fd46167SDavid du Colombier 		return;
6707fd46167SDavid du Colombier 	}
6717fd46167SDavid du Colombier 	if((ulong)~r->d.atime != 0){
6727fd46167SDavid du Colombier 		respond(r, "wstat -- attempt to change atime");
6737fd46167SDavid du Colombier 		return;
6747fd46167SDavid du Colombier 	}
6757fd46167SDavid du Colombier 	if((ulong)~r->d.mode && (r->d.mode&DMDIR) != (r->fid->qid.type&DMDIR)){
6767fd46167SDavid du Colombier 		respond(r, "wstat -- attempt to change DMDIR bit");
6777fd46167SDavid du Colombier 		return;
6787fd46167SDavid du Colombier 	}
6797fd46167SDavid du Colombier 	srv->wstat(r);
6807fd46167SDavid du Colombier }
6817fd46167SDavid du Colombier static void
6827fd46167SDavid du Colombier rwstat(Req*, char*)
6837fd46167SDavid du Colombier {
6847fd46167SDavid du Colombier }
6857fd46167SDavid du Colombier 
6867fd46167SDavid du Colombier void
6877fd46167SDavid du Colombier srv(Srv *srv)
6887fd46167SDavid du Colombier {
6897fd46167SDavid du Colombier 	Req *r;
6907fd46167SDavid du Colombier 
6917fd46167SDavid du Colombier 	fmtinstall('D', dirfmt);
6927fd46167SDavid du Colombier 	fmtinstall('F', fcallfmt);
6937fd46167SDavid du Colombier 
6947fd46167SDavid du Colombier 	if(srv->fpool == nil)
6957fd46167SDavid du Colombier 		srv->fpool = allocfidpool(srv->destroyfid);
6967fd46167SDavid du Colombier 	if(srv->rpool == nil)
6977fd46167SDavid du Colombier 		srv->rpool = allocreqpool(srv->destroyreq);
6987fd46167SDavid du Colombier 	if(srv->msize == 0)
6997fd46167SDavid du Colombier 		srv->msize = 8192+IOHDRSZ;
7007fd46167SDavid du Colombier 
7017fd46167SDavid du Colombier 	changemsize(srv, srv->msize);
7027fd46167SDavid du Colombier 
7037fd46167SDavid du Colombier 	srv->fpool->srv = srv;
7047fd46167SDavid du Colombier 	srv->rpool->srv = srv;
7057fd46167SDavid du Colombier 
7067fd46167SDavid du Colombier 	while(r = getreq(srv)){
7077fd46167SDavid du Colombier 		if(r->error){
7087fd46167SDavid du Colombier 			respond(r, r->error);
7097fd46167SDavid du Colombier 			continue;
7107fd46167SDavid du Colombier 		}
7117fd46167SDavid du Colombier 		switch(r->ifcall.type){
7127fd46167SDavid du Colombier 		default:
7137fd46167SDavid du Colombier 			respond(r, "unknown message");
7147dd7cddfSDavid du Colombier 			break;
7157fd46167SDavid du Colombier 		case Tversion:	sversion(srv, r);	break;
7167fd46167SDavid du Colombier 		case Tauth:	sauth(srv, r);	break;
7177fd46167SDavid du Colombier 		case Tattach:	sattach(srv, r);	break;
7187fd46167SDavid du Colombier 		case Tflush:	sflush(srv, r);	break;
7197fd46167SDavid du Colombier 		case Twalk:	swalk(srv, r);	break;
7207fd46167SDavid du Colombier 		case Topen:	sopen(srv, r);	break;
7217fd46167SDavid du Colombier 		case Tcreate:	screate(srv, r);	break;
7227fd46167SDavid du Colombier 		case Tread:	sread(srv, r);	break;
7237fd46167SDavid du Colombier 		case Twrite:	swrite(srv, r);	break;
7247fd46167SDavid du Colombier 		case Tclunk:	sclunk(srv, r);	break;
7257fd46167SDavid du Colombier 		case Tremove:	sremove(srv, r);	break;
7267fd46167SDavid du Colombier 		case Tstat:	sstat(srv, r);	break;
7277fd46167SDavid du Colombier 		case Twstat:	swstat(srv, r);	break;
7287dd7cddfSDavid du Colombier 		}
7297dd7cddfSDavid du Colombier 	}
7303ff48bf5SDavid du Colombier 
7313ff48bf5SDavid du Colombier 	if(srv->end)
7323ff48bf5SDavid du Colombier 		srv->end(srv);
7337dd7cddfSDavid du Colombier }
7347dd7cddfSDavid du Colombier 
7357dd7cddfSDavid du Colombier void
7367dd7cddfSDavid du Colombier respond(Req *r, char *error)
7377dd7cddfSDavid du Colombier {
7387fd46167SDavid du Colombier 	int i, m, n;
7399a747e4fSDavid du Colombier 	char errbuf[ERRMAX];
7407dd7cddfSDavid du Colombier 	Srv *srv;
7417dd7cddfSDavid du Colombier 
7429a747e4fSDavid du Colombier 	srv = r->srv;
7439a747e4fSDavid du Colombier 	assert(srv != nil);
7449a747e4fSDavid du Colombier 
7457dd7cddfSDavid du Colombier 	assert(r->responded == 0);
7467fd46167SDavid du Colombier 	r->error = error;
7477dd7cddfSDavid du Colombier 
7489a747e4fSDavid du Colombier 	switch(r->ifcall.type){
7497dd7cddfSDavid du Colombier 	default:
7509a747e4fSDavid du Colombier 		assert(0);
7517fd46167SDavid du Colombier 	/*
7527fd46167SDavid du Colombier 	 * Flush is special.  If the handler says so, we return
7537fd46167SDavid du Colombier 	 * without further processing.  Respond will be called
7547fd46167SDavid du Colombier 	 * again once it is safe.
7557fd46167SDavid du Colombier 	 */
7569a747e4fSDavid du Colombier 	case Tflush:
7577fd46167SDavid du Colombier 		if(rflush(r, error)<0)
7587fd46167SDavid du Colombier 			return;
7597dd7cddfSDavid du Colombier 		break;
7607fd46167SDavid du Colombier 	case Tversion:	rversion(r, error);	break;
7617fd46167SDavid du Colombier 	case Tauth:	rauth(r, error);	break;
7627fd46167SDavid du Colombier 	case Tattach:	rattach(r, error);	break;
7637fd46167SDavid du Colombier 	case Twalk:	rwalk(r, error);	break;
7647fd46167SDavid du Colombier 	case Topen:	ropen(r, error);	break;
7657fd46167SDavid du Colombier 	case Tcreate:	rcreate(r, error);	break;
7667fd46167SDavid du Colombier 	case Tread:	rread(r, error);	break;
7677fd46167SDavid du Colombier 	case Twrite:	rwrite(r, error);	break;
7687fd46167SDavid du Colombier 	case Tclunk:	rclunk(r, error);	break;
7697fd46167SDavid du Colombier 	case Tremove:	rremove(r, error, errbuf);	break;
7707fd46167SDavid du Colombier 	case Tstat:	rstat(r, error);	break;
7717fd46167SDavid du Colombier 	case Twstat:	rwstat(r, error);	break;
7727dd7cddfSDavid du Colombier 	}
7737dd7cddfSDavid du Colombier 
7749a747e4fSDavid du Colombier 	r->ofcall.tag = r->ifcall.tag;
7759a747e4fSDavid du Colombier 	r->ofcall.type = r->ifcall.type+1;
7767fd46167SDavid du Colombier 	if(r->error)
7777fd46167SDavid du Colombier 		setfcallerror(&r->ofcall, r->error);
7787dd7cddfSDavid du Colombier 
7799a747e4fSDavid du Colombier if(chatty9p)
7809a747e4fSDavid du Colombier 	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);
7817dd7cddfSDavid du Colombier 
7829a747e4fSDavid du Colombier 	qlock(&srv->wlock);
7839a747e4fSDavid du Colombier 	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
7849a747e4fSDavid du Colombier 	if(n <= 0){
7859a747e4fSDavid du Colombier 		fprint(2, "n = %d %F\n", n, &r->ofcall);
7869a747e4fSDavid du Colombier 		abort();
7879a747e4fSDavid du Colombier 	}
7889a747e4fSDavid du Colombier 	assert(n > 2);
7897fd46167SDavid du Colombier 	if(r->pool)	/* not a fake */
7909a747e4fSDavid du Colombier 		closereq(removereq(r->pool, r->ifcall.tag));
7915d459b5aSDavid du Colombier 	m = write(srv->outfd, srv->wbuf, n);
7925d459b5aSDavid du Colombier 	if(m != n)
7935d459b5aSDavid du Colombier 		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
7945d459b5aSDavid du Colombier 	qunlock(&srv->wlock);
7955d459b5aSDavid du Colombier 
7967fd46167SDavid du Colombier 	qlock(&r->lk);	/* no one will add flushes now */
7977fd46167SDavid du Colombier 	r->responded = 1;
7987fd46167SDavid du Colombier 	qunlock(&r->lk);
7997fd46167SDavid du Colombier 
8007fd46167SDavid du Colombier 	for(i=0; i<r->nflush; i++)
8017fd46167SDavid du Colombier 		respond(r->flush[i], nil);
8027fd46167SDavid du Colombier 	free(r->flush);
8037fd46167SDavid du Colombier 
8047fd46167SDavid du Colombier 	if(r->pool)
8057fd46167SDavid du Colombier 		closereq(r);
8067fd46167SDavid du Colombier 	else
8077fd46167SDavid du Colombier 		free(r);
8087dd7cddfSDavid du Colombier }
8097dd7cddfSDavid du Colombier 
8109a747e4fSDavid du Colombier int
8119a747e4fSDavid du Colombier postfd(char *name, int pfd)
8127dd7cddfSDavid du Colombier {
8137dd7cddfSDavid du Colombier 	int fd;
8149a747e4fSDavid du Colombier 	char buf[80];
8157dd7cddfSDavid du Colombier 
8167dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "/srv/%s", name);
8179a747e4fSDavid du Colombier 	if(chatty9p)
8189a747e4fSDavid du Colombier 		fprint(2, "postfd %s\n", buf);
8199a747e4fSDavid du Colombier 	fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600);
8209a747e4fSDavid du Colombier 	if(fd < 0){
8219a747e4fSDavid du Colombier 		if(chatty9p)
8229a747e4fSDavid du Colombier 			fprint(2, "create fails: %r\n");
8239a747e4fSDavid du Colombier 		return -1;
8247dd7cddfSDavid du Colombier 	}
8259a747e4fSDavid du Colombier 	if(fprint(fd, "%d", pfd) < 0){
8269a747e4fSDavid du Colombier 		if(chatty9p)
8279a747e4fSDavid du Colombier 			fprint(2, "write fails: %r\n");
8289a747e4fSDavid du Colombier 		close(fd);
8299a747e4fSDavid du Colombier 		return -1;
8307dd7cddfSDavid du Colombier 	}
8319a747e4fSDavid du Colombier 	if(chatty9p)
8329a747e4fSDavid du Colombier 		fprint(2, "postfd successful\n");
8339a747e4fSDavid du Colombier 	return 0;
8347dd7cddfSDavid du Colombier }
8357dd7cddfSDavid du Colombier 
836