Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <auth.h>
4
#include <fcall.h>
5
#include <thread.h>
6
#include <9p.h>
7
 
8
void (*_forker)(void(*)(void*), void*, int);
9
 
10
static char Ebadattach[] = "unknown specifier in attach";
11
static char Ebadoffset[] = "bad offset";
12
static char Ebadcount[] = "bad count";
13
static char Ebotch[] = "9P protocol botch";
14
static char Ecreatenondir[] = "create in non-directory";
15
static char Edupfid[] = "duplicate fid";
16
static char Eduptag[] = "duplicate tag";
17
static char Eisdir[] = "is a directory";
18
static char Enocreate[] = "create prohibited";
19
static char Enomem[] = "out of memory";
20
static char Enoremove[] = "remove prohibited";
21
static char Enostat[] = "stat prohibited";
22
static char Enotfound[] = "file not found";
23
static char Enowrite[] = "write prohibited";
24
static char Enowstat[] = "wstat prohibited";
25
static char Eperm[] = "permission denied";
26
static char Eunknownfid[] = "unknown fid";
27
static char Ebaddir[] = "bad directory in wstat";
28
static char Ewalknodir[] = "walk in non-directory";
29
 
30
static void
31
setfcallerror(Fcall *f, char *err)
32
{
33
	f->ename = err;
34
	f->type = Rerror;
35
}
36
 
37
static void
38
changemsize(Srv *srv, int msize)
39
{
40
	if(srv->rbuf && srv->wbuf && srv->msize == msize)
41
		return;
42
	qlock(&srv->rlock);
43
	qlock(&srv->wlock);
44
	srv->msize = msize;
45
	free(srv->rbuf);
46
	free(srv->wbuf);
47
	srv->rbuf = emalloc9p(msize);
48
	srv->wbuf = emalloc9p(msize);
49
	qunlock(&srv->rlock);
50
	qunlock(&srv->wlock);
51
}
52
 
53
static Req*
54
getreq(Srv *s)
55
{
56
	long n;
57
	uchar *buf;
58
	Fcall f;
59
	Req *r;
60
 
61
	qlock(&s->rlock);
62
	if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){
63
		qunlock(&s->rlock);
64
		return nil;
65
	}
66
 
67
	buf = emalloc9p(n);
68
	memmove(buf, s->rbuf, n);
69
	qunlock(&s->rlock);
70
 
71
	if(convM2S(buf, n, &f) != n){
72
		free(buf);
73
		return nil;
74
	}
75
 
76
	if((r=allocreq(s->rpool, f.tag)) == nil){	/* duplicate tag: cons up a fake Req */
77
		r = emalloc9p(sizeof *r);
78
		incref(&r->ref);
79
		r->tag = f.tag;
80
		r->ifcall = f;
81
		r->error = Eduptag;
82
		r->buf = buf;
83
		r->responded = 0;
84
		r->type = 0;
85
		r->srv = s;
86
		r->pool = nil;
87
if(chatty9p)
88
	fprint(2, "<-%d- %F: dup tag\n", s->infd, &f);
89
		return r;
90
	}
91
 
92
	r->srv = s;
93
	r->responded = 0;
94
	r->buf = buf;
95
	r->ifcall = f;
96
	memset(&r->ofcall, 0, sizeof r->ofcall);
97
	r->type = r->ifcall.type;
98
 
99
if(chatty9p)
100
	if(r->error)
101
		fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error);
102
	else	
103
		fprint(2, "<-%d- %F\n", s->infd, &r->ifcall);
104
 
105
	return r;
106
}
107
 
108
static void
109
filewalk(Req *r)
110
{
111
	int i;
112
	File *f;
113
 
114
	f = r->fid->file;
115
	assert(f != nil);
116
 
117
	incref(f);
118
	for(i=0; i<r->ifcall.nwname; i++)
119
		if(f = walkfile(f, r->ifcall.wname[i]))
120
			r->ofcall.wqid[i] = f->qid;
121
		else
122
			break;
123
 
124
	r->ofcall.nwqid = i;
125
	if(f){
126
		r->newfid->file = f;
127
		r->newfid->qid = r->newfid->file->qid;
128
	}
129
	respond(r, nil);
130
}
131
 
132
void
133
walkandclone(Req *r, char *(*walk1)(Fid*, char*, void*), char *(*clone)(Fid*, Fid*, void*), void *arg)
134
{
135
	int i;
136
	char *e;
137
 
138
	if(r->fid == r->newfid && r->ifcall.nwname > 1){
139
		respond(r, "lib9p: unused documented feature not implemented");
140
		return;
141
	}
142
 
143
	if(r->fid != r->newfid){
144
		r->newfid->qid = r->fid->qid;
145
		if(clone && (e = clone(r->fid, r->newfid, arg))){
146
			respond(r, e);
147
			return;
148
		}
149
	}
150
 
151
	e = nil;
152
	for(i=0; i<r->ifcall.nwname; i++){
153
		if(e = walk1(r->newfid, r->ifcall.wname[i], arg))
154
			break;
155
		r->ofcall.wqid[i] = r->newfid->qid;
156
	}
157
 
158
	r->ofcall.nwqid = i;
159
	if(e && i==0)
160
		respond(r, e);
161
	else
162
		respond(r, nil);
163
}
164
 
165
static void
166
sversion(Srv*, Req *r)
167
{
168
	if(strncmp(r->ifcall.version, "9P", 2) != 0){
169
		r->ofcall.version = "unknown";
170
		respond(r, nil);
171
		return;
172
	}
173
 
174
	r->ofcall.version = "9P2000";
175
	r->ofcall.msize = r->ifcall.msize;
176
	respond(r, nil);
177
}
178
static void
179
rversion(Req *r, char *error)
180
{
181
	assert(error == nil);
182
	changemsize(r->srv, r->ofcall.msize);
183
}
184
 
185
static void
186
sauth(Srv *srv, Req *r)
187
{
188
	char e[ERRMAX];
189
 
190
	if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){
191
		respond(r, Edupfid);
192
		return;
193
	}
194
	if(srv->auth)
195
		srv->auth(r);
196
	else{
197
		snprint(e, sizeof e, "%s: authentication not required", argv0);
198
		respond(r, e);
199
	}
200
}
201
static void
202
rauth(Req *r, char *error)
203
{
204
	if(error && r->afid)
205
		closefid(removefid(r->srv->fpool, r->afid->fid));
206
}
207
 
208
static void
209
sattach(Srv *srv, Req *r)
210
{
211
	if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){
212
		respond(r, Edupfid);
213
		return;
214
	}
215
	r->afid = nil;
216
	if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){
217
		respond(r, Eunknownfid);
218
		return;
219
	}
220
	r->fid->uid = estrdup9p(r->ifcall.uname);
221
	if(srv->tree){
222
		r->fid->file = srv->tree->root;
223
		incref(r->fid->file);
224
		r->ofcall.qid = r->fid->file->qid;
225
		r->fid->qid = r->ofcall.qid;
226
	}
227
	if(srv->attach)
228
		srv->attach(r);
229
	else
230
		respond(r, nil);
231
	return;
232
}
233
static void
234
rattach(Req *r, char *error)
235
{
236
	if(error && r->fid)
237
		closefid(removefid(r->srv->fpool, r->fid->fid));
238
}
239
 
240
static void
241
sflush(Srv *srv, Req *r)
242
{
243
	r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag);
244
	if(r->oldreq == nil || r->oldreq == r)
245
		respond(r, nil);
246
	else if(srv->flush)
247
		srv->flush(r);
248
	else
249
		respond(r, nil);
250
}
251
static int
252
rflush(Req *r, char *error)
253
{
254
	Req *or;
255
 
256
	assert(error == nil);
257
	or = r->oldreq;
258
	if(or){
259
		qlock(&or->lk);
260
		if(or->responded == 0){
261
			or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0]));
262
			or->flush[or->nflush++] = r;
263
			qunlock(&or->lk);
264
			return -1;		/* delay response until or is responded */
265
		}
266
		qunlock(&or->lk);
267
		closereq(or);
268
	}
269
	r->oldreq = nil;
270
	return 0;
271
}
272
 
273
static char*
274
oldwalk1(Fid *fid, char *name, void *arg)
275
{
276
	char *e;
277
	Qid qid;
278
	Srv *srv;
279
 
280
	srv = arg;
281
	e = srv->walk1(fid, name, &qid);
282
	if(e)
283
		return e;
284
	fid->qid = qid;
285
	return nil;
286
}
287
 
288
static char*
289
oldclone(Fid *fid, Fid *newfid, void *arg)
290
{
291
	Srv *srv;
292
 
293
	srv = arg;
294
	if(srv->clone == nil)
295
		return nil;
296
	return srv->clone(fid, newfid);
297
}
298
 
299
static void
300
swalk(Srv *srv, Req *r)
301
{
302
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
303
		respond(r, Eunknownfid);
304
		return;
305
	}
306
	if(r->fid->omode != -1){
307
		respond(r, "cannot clone open fid");
308
		return;
309
	}
310
	if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){
311
		respond(r, Ewalknodir);
312
		return;
313
	}
314
	if(r->ifcall.fid != r->ifcall.newfid){
315
		if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){
316
			respond(r, Edupfid);
317
			return;
318
		}
319
		r->newfid->uid = estrdup9p(r->fid->uid);
320
	}else{
321
		incref(&r->fid->ref);
322
		r->newfid = r->fid;
323
	}
324
	if(r->fid->file){
325
		filewalk(r);
326
	}else if(srv->walk1)
327
		walkandclone(r, oldwalk1, oldclone, srv);
328
	else if(srv->walk)
329
		srv->walk(r);
330
	else
331
		sysfatal("no walk function, no file trees");
332
}
333
static void
334
rwalk(Req *r, char *error)
335
{
336
	if(error || r->ofcall.nwqid < r->ifcall.nwname){
337
		if(r->ifcall.fid != r->ifcall.newfid && r->newfid)
338
			closefid(removefid(r->srv->fpool, r->newfid->fid));
339
		if (r->ofcall.nwqid==0){
340
			if(error==nil && r->ifcall.nwname!=0)
341
				r->error = Enotfound;
342
		}else
343
			r->error = nil;	// No error on partial walks
344
	}else{
345
		if(r->ofcall.nwqid == 0){
346
			/* Just a clone */
347
			r->newfid->qid = r->fid->qid;
348
		}else{
349
			/* if file trees are in use, filewalk took care of the rest */
350
			r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1];
351
		}
352
	}
353
}
354
 
355
static void
356
sopen(Srv *srv, Req *r)
357
{
358
	int p;
359
 
360
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
361
		respond(r, Eunknownfid);
362
		return;
363
	}
364
	if(r->fid->omode != -1){
365
		respond(r, Ebotch);
366
		return;
367
	}
368
	if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){
369
		respond(r, Eisdir);
370
		return;
371
	}
372
	r->ofcall.qid = r->fid->qid;
373
	switch(r->ifcall.mode&3){
374
	default:
375
		assert(0);
376
	case OREAD:
377
		p = AREAD;	
378
		break;
379
	case OWRITE:
380
		p = AWRITE;
381
		break;
382
	case ORDWR:
383
		p = AREAD|AWRITE;
384
		break;
385
	case OEXEC:
386
		p = AEXEC;	
387
		break;
388
	}
389
	if(r->ifcall.mode&OTRUNC)
390
		p |= AWRITE;
391
	if((r->fid->qid.type&QTDIR) && p!=AREAD){
392
		respond(r, Eperm);
393
		return;
394
	}
395
	if(r->fid->file){
396
		if(!hasperm(r->fid->file, r->fid->uid, p)){
397
			respond(r, Eperm);
398
			return;
399
		}
400
	/* BUG RACE */
401
		if((r->ifcall.mode&ORCLOSE)
402
		&& !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
403
			respond(r, Eperm);
404
			return;
405
		}
406
		r->ofcall.qid = r->fid->file->qid;
407
		if((r->ofcall.qid.type&QTDIR)
408
		&& (r->fid->rdir = opendirfile(r->fid->file)) == nil){
409
			respond(r, "opendirfile failed");
410
			return;
411
		}
412
	}
413
	if(srv->open)
414
		srv->open(r);
415
	else
416
		respond(r, nil);
417
}
418
static void
419
ropen(Req *r, char *error)
420
{
421
	char errbuf[ERRMAX];
422
	if(error)
423
		return;
424
	if(chatty9p){
425
		snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode);
426
		write(2, errbuf, strlen(errbuf));
427
	}
428
	r->fid->omode = r->ifcall.mode;
429
	r->fid->qid = r->ofcall.qid;
430
	if(r->ofcall.qid.type&QTDIR)
431
		r->fid->diroffset = 0;
432
}
433
 
434
static void
435
screate(Srv *srv, Req *r)
436
{
437
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil)
438
		respond(r, Eunknownfid);
439
	else if(r->fid->omode != -1)
440
		respond(r, Ebotch);
441
	else if(!(r->fid->qid.type&QTDIR))
442
		respond(r, Ecreatenondir);
443
	else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE))
444
		respond(r, Eperm);
445
	else if(srv->create)
446
		srv->create(r);
447
	else
448
		respond(r, Enocreate);
449
}
450
static void
451
rcreate(Req *r, char *error)
452
{
453
	if(error)
454
		return;
455
	r->fid->omode = r->ifcall.mode;
456
	r->fid->qid = r->ofcall.qid;
457
}
458
 
459
static void
460
sread(Srv *srv, Req *r)
461
{
462
	int o;
463
 
464
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
465
		respond(r, Eunknownfid);
466
		return;
467
	}
468
	if((int)r->ifcall.count < 0){
469
		respond(r, Ebotch);
470
		return;
471
	}
472
	if(r->ifcall.offset < 0
473
	|| ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){
474
		respond(r, Ebadoffset);
475
		return;
476
	}
477
 
478
	if(r->ifcall.count > srv->msize - IOHDRSZ)
479
		r->ifcall.count = srv->msize - IOHDRSZ;
480
	r->rbuf = emalloc9p(r->ifcall.count);
481
	r->ofcall.data = r->rbuf;
482
	o = r->fid->omode & 3;
483
	if(o != OREAD && o != ORDWR && o != OEXEC){
484
		respond(r, Ebotch);
485
		return;
486
	}
487
	if((r->fid->qid.type&QTDIR) && r->fid->file){
488
		r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count);
489
		respond(r, nil);
490
		return;
491
	}
492
	if(srv->read)
493
		srv->read(r);
494
	else
495
		respond(r, "no srv->read");
496
}
497
static void
498
rread(Req *r, char *error)
499
{
500
	if(error==nil && (r->fid->qid.type&QTDIR))
501
		r->fid->diroffset += r->ofcall.count;
502
}
503
 
504
static void
505
swrite(Srv *srv, Req *r)
506
{
507
	int o;
508
	char e[ERRMAX];
509
 
510
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
511
		respond(r, Eunknownfid);
512
		return;
513
	}
514
	if((int)r->ifcall.count < 0){
515
		respond(r, Ebotch);
516
		return;
517
	}
518
	if(r->ifcall.offset < 0){
519
		respond(r, Ebotch);
520
		return;
521
	}
522
	if(r->ifcall.count > srv->msize - IOHDRSZ)
523
		r->ifcall.count = srv->msize - IOHDRSZ;
524
	o = r->fid->omode & 3;
525
	if(o != OWRITE && o != ORDWR){
526
		snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode);
527
		respond(r, e);
528
		return;
529
	}
530
	if(srv->write)
531
		srv->write(r);
532
	else
533
		respond(r, "no srv->write");
534
}
535
static void
536
rwrite(Req *r, char *error)
537
{
538
	if(error)
539
		return;
540
	if(r->fid->file)
541
		r->fid->file->qid.vers++;
542
}
543
 
544
static void
545
sclunk(Srv *srv, Req *r)
546
{
547
	if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil)
548
		respond(r, Eunknownfid);
549
	else
550
		respond(r, nil);
551
}
552
static void
553
rclunk(Req*, char*)
554
{
555
}
556
 
557
static void
558
sremove(Srv *srv, Req *r)
559
{
560
	if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){
561
		respond(r, Eunknownfid);
562
		return;
563
	}
564
	/* BUG RACE */
565
	if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
566
		respond(r, Eperm);
567
		return;
568
	}
569
	if(srv->remove)
570
		srv->remove(r);
571
	else
572
		respond(r, r->fid->file ? nil : Enoremove);
573
}
574
static void
575
rremove(Req *r, char *error, char *errbuf)
576
{
577
	if(error)
578
		return;
579
	if(r->fid->file){
580
		if(removefile(r->fid->file) < 0){
581
			snprint(errbuf, ERRMAX, "remove %s: %r", 
582
				r->fid->file->name);
583
			r->error = errbuf;
584
		}
585
		r->fid->file = nil;
586
	}
587
}
588
 
589
static void
590
sstat(Srv *srv, Req *r)
591
{
592
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
593
		respond(r, Eunknownfid);
594
		return;
595
	}
596
	if(r->fid->file){
597
		/* should we rlock the file? */
598
		r->d = r->fid->file->Dir;
599
		if(r->d.name)
600
			r->d.name = estrdup9p(r->d.name);
601
		if(r->d.uid)
602
			r->d.uid = estrdup9p(r->d.uid);
603
		if(r->d.gid)
604
			r->d.gid = estrdup9p(r->d.gid);
605
		if(r->d.muid)
606
			r->d.muid = estrdup9p(r->d.muid);
607
	}
608
	if(srv->stat)	
609
		srv->stat(r);	
610
	else if(r->fid->file)
611
		respond(r, nil);
612
	else
613
		respond(r, Enostat);
614
}
615
static void
616
rstat(Req *r, char *error)
617
{
618
	int n;
619
	uchar *statbuf;
620
	uchar tmp[BIT16SZ];
621
 
622
	if(error)
623
		return;
624
	if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){
625
		r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ";
626
		return;
627
	}
628
	n = GBIT16(tmp)+BIT16SZ;
629
	statbuf = emalloc9p(n);
630
	if(statbuf == nil){
631
		r->error = "out of memory";
632
		return;
633
	}
634
	r->ofcall.nstat = convD2M(&r->d, statbuf, n);
635
	r->ofcall.stat = statbuf;	/* freed in closereq */
636
	if(r->ofcall.nstat <= BIT16SZ){
637
		r->error = "convD2M fails";
638
		free(statbuf);
639
		return;
640
	}
641
}
642
 
643
static void
644
swstat(Srv *srv, Req *r)
645
{
646
	if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
647
		respond(r, Eunknownfid);
648
		return;
649
	}
650
	if(srv->wstat == nil){
651
		respond(r, Enowstat);
652
		return;
653
	}
654
	if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){
655
		respond(r, Ebaddir);
656
		return;
657
	}
658
	if((ushort)~r->d.type){
659
		respond(r, "wstat -- attempt to change type");
660
		return;
661
	}
662
	if((uint)~r->d.dev){
663
		respond(r, "wstat -- attempt to change dev");
664
		return;
665
	}
666
	if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){
667
		respond(r, "wstat -- attempt to change qid");
668
		return;
669
	}
670
	if(r->d.muid && r->d.muid[0]){
671
		respond(r, "wstat -- attempt to change muid");
672
		return;
673
	}
674
	if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){
675
		respond(r, "wstat -- attempt to change DMDIR bit");
676
		return;
677
	}
678
	srv->wstat(r);
679
}
680
static void
681
rwstat(Req*, char*)
682
{
683
}
684
 
685
void
686
srv(Srv *srv)
687
{
688
	Req *r;
689
 
690
	fmtinstall('D', dirfmt);
691
	fmtinstall('F', fcallfmt);
692
 
693
	if(srv->fpool == nil)
694
		srv->fpool = allocfidpool(srv->destroyfid);
695
	if(srv->rpool == nil)
696
		srv->rpool = allocreqpool(srv->destroyreq);
697
	if(srv->msize == 0)
698
		srv->msize = 8192+IOHDRSZ;
699
 
700
	changemsize(srv, srv->msize);
701
 
702
	srv->fpool->srv = srv;
703
	srv->rpool->srv = srv;
704
 
705
	while(r = getreq(srv)){
706
		if(r->error){
707
			respond(r, r->error);
708
			continue;	
709
		}
710
		switch(r->ifcall.type){
711
		default:
712
			respond(r, "unknown message");
713
			break;
714
		case Tversion:	sversion(srv, r);	break;
715
		case Tauth:	sauth(srv, r);	break;
716
		case Tattach:	sattach(srv, r);	break;
717
		case Tflush:	sflush(srv, r);	break;
718
		case Twalk:	swalk(srv, r);	break;
719
		case Topen:	sopen(srv, r);	break;
720
		case Tcreate:	screate(srv, r);	break;
721
		case Tread:	sread(srv, r);	break;
722
		case Twrite:	swrite(srv, r);	break;
723
		case Tclunk:	sclunk(srv, r);	break;
724
		case Tremove:	sremove(srv, r);	break;
725
		case Tstat:	sstat(srv, r);	break;
726
		case Twstat:	swstat(srv, r);	break;
727
		}
728
	}
729
 
730
	free(srv->rbuf);
731
	srv->rbuf = nil;
732
	free(srv->wbuf);
733
	srv->wbuf = nil;
734
	srv->msize = 0;
735
	freefidpool(srv->fpool);
736
	srv->fpool = nil;
737
	freereqpool(srv->rpool);
738
	srv->rpool = nil;
739
 
740
	if(srv->end)
741
		srv->end(srv);
742
}
743
 
744
void
745
respond(Req *r, char *error)
746
{
747
	int i, m, n;
748
	char errbuf[ERRMAX];
749
	Srv *srv;
750
 
751
	srv = r->srv;
752
	assert(srv != nil);
753
 
754
	assert(r->responded == 0);
755
	r->error = error;
756
 
757
	switch(r->ifcall.type){
758
	default:
759
		assert(0);
760
	/*
761
	 * Flush is special.  If the handler says so, we return
762
	 * without further processing.  Respond will be called
763
	 * again once it is safe.
764
	 */
765
	case Tflush:
766
		if(rflush(r, error)<0)
767
			return;
768
		break;
769
	case Tversion:	rversion(r, error);	break;
770
	case Tauth:	rauth(r, error);	break;
771
	case Tattach:	rattach(r, error);	break;
772
	case Twalk:	rwalk(r, error);	break;
773
	case Topen:	ropen(r, error);	break;
774
	case Tcreate:	rcreate(r, error);	break;
775
	case Tread:	rread(r, error);	break;
776
	case Twrite:	rwrite(r, error);	break;
777
	case Tclunk:	rclunk(r, error);	break;
778
	case Tremove:	rremove(r, error, errbuf);	break;
779
	case Tstat:	rstat(r, error);	break;
780
	case Twstat:	rwstat(r, error);	break;
781
	}
782
 
783
	r->ofcall.tag = r->ifcall.tag;
784
	r->ofcall.type = r->ifcall.type+1;
785
	if(r->error)
786
		setfcallerror(&r->ofcall, r->error);
787
 
788
if(chatty9p)
789
	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);
790
 
791
	qlock(&srv->wlock);
792
	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
793
	if(n <= 0){
794
		fprint(2, "n = %d %F\n", n, &r->ofcall);
795
		abort();
796
	}
797
	assert(n > 2);
798
	if(r->pool)	/* not a fake */
799
		closereq(removereq(r->pool, r->ifcall.tag));
800
	m = write(srv->outfd, srv->wbuf, n);
801
	if(m != n)
802
		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
803
	qunlock(&srv->wlock);
804
 
805
	qlock(&r->lk);	/* no one will add flushes now */
806
	r->responded = 1;
807
	qunlock(&r->lk);
808
 
809
	for(i=0; i<r->nflush; i++)
810
		respond(r->flush[i], nil);
811
	free(r->flush);
812
	r->flush = nil;
813
	r->nflush = 0;
814
 
815
	if(r->pool)
816
		closereq(r);
817
	else
818
		free(r);
819
}
820
 
821
void
822
responderror(Req *r)
823
{
824
	char errbuf[ERRMAX];
825
 
826
	rerrstr(errbuf, sizeof errbuf);
827
	respond(r, errbuf);
828
}
829
 
830
int
831
postfd(char *name, int pfd)
832
{
833
	int fd;
834
	char buf[80];
835
 
836
	snprint(buf, sizeof buf, "/srv/%s", name);
837
	if(chatty9p)
838
		fprint(2, "postfd %s\n", buf);
839
	fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600);
840
	if(fd < 0){
841
		if(chatty9p)
842
			fprint(2, "create fails: %r\n");
843
		return -1;
844
	}
845
	if(fprint(fd, "%d", pfd) < 0){
846
		if(chatty9p)
847
			fprint(2, "write fails: %r\n");
848
		close(fd);
849
		return -1;
850
	}
851
	if(chatty9p)
852
		fprint(2, "postfd successful\n");
853
	return 0;
854
}
855