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 "all.h"
2
#include "9p1.h"
3
 
4
extern Nvrsafe	nvr;
5
 
6
typedef struct {
7
	uchar	chal[CHALLEN];		/* locally generated challenge */
8
	uchar	rchal[CHALLEN];		/* remotely generated challenge */
9
	Lock	idlock;
10
	ulong	idoffset;		/* offset of id vector */
11
	ulong	idvec;			/* vector of acceptable id's */
12
} Authinfo;
13
 
14
static void
15
f_nop(Chan *cp, Fcall*, Fcall*)
16
{
17
	if(CHAT(cp))
18
		print("c_nop %d\n", cp->chan);
19
}
20
 
21
static void
22
f_flush(Chan *cp, Fcall*, Fcall*)
23
{
24
	if(CHAT(cp))
25
		print("c_flush %d\n", cp->chan);
26
	runlock(&cp->reflock);
27
	wlock(&cp->reflock);
28
	wunlock(&cp->reflock);
29
	rlock(&cp->reflock);
30
}
31
 
32
/*
33
 *  create a challenge for a fid space
34
 */
35
static void
36
mkchallenge(Authinfo *aip)
37
{
38
	int i;
39
 
40
	srand((uintptr)aip + time(nil));
41
	for(i = 0; i < CHALLEN; i++)
42
		aip->chal[i] = nrand(256);
43
 
44
	aip->idoffset = 0;
45
	aip->idvec = 0;
46
}
47
 
48
static void
49
f_session(Chan *cp, Fcall *in, Fcall *ou)
50
{
51
	Authinfo *aip;
52
 
53
	aip = (Authinfo*)cp->authinfo;
54
 
55
	if(CHAT(cp))
56
		print("c_session %d\n", cp->chan);
57
	memmove(aip->rchal, in->chal, sizeof(aip->rchal));
58
	mkchallenge(aip);
59
	memmove(ou->chal, aip->chal, sizeof(ou->chal));
60
	if(noauth || wstatallow)
61
		memset(ou->authid, 0, sizeof(ou->authid));
62
	else
63
		memmove(ou->authid, nvr.authid, sizeof(ou->authid));
64
 
65
	sprint(ou->authdom, "%s.%s", service, nvr.authdom);
66
	fileinit(cp);
67
}
68
 
69
/*
70
 *  match a challenge from an attach
71
 */
72
static int
73
authorize(Chan *cp, Fcall *in, Fcall *ou)
74
{
75
	Ticket t;
76
	Authenticator a;
77
	int x;
78
	ulong bit;
79
	Authinfo *aip;
80
 
81
	if(noauth || wstatallow)	/* set to allow entry during boot */
82
		return 1;
83
 
84
	if(strcmp(in->uname, "none") == 0)
85
		return 1;
86
 
87
	if(in->type == Toattach)
88
		return 0;
89
 
90
	/* decrypt and unpack ticket */
91
	convM2T9p1(in->ticket, &t, nvr.machkey);
92
	if(t.num != AuthTs){
93
		print("9p1: bad AuthTs num\n");
94
		return 0;
95
	}
96
 
97
	/* decrypt and unpack authenticator */
98
	convM2A9p1(in->auth, &a, t.key);
99
	if(a.num != AuthAc){
100
		print("9p1: bad AuthAc num\n");
101
		return 0;
102
	}
103
 
104
	/* challenges must match */
105
	aip = (Authinfo*)cp->authinfo;
106
	if(memcmp(a.chal, aip->chal, sizeof(a.chal)) != 0){
107
		print("9p1: bad challenge\n");
108
		return 0;
109
	}
110
 
111
	/*
112
	 *  the id must be in a valid range.  the range is specified by a
113
	 *  lower bound (idoffset) and a bit vector (idvec) where a
114
	 *  bit set to 1 means unusable
115
	 */
116
	lock(&aip->idlock);
117
	x = a.id - aip->idoffset;
118
	bit = 1<<x;
119
	if(x < 0 || x > 31 || (bit&aip->idvec)){
120
		unlock(&aip->idlock);
121
		print("9p1: id out of range: idoff %ld idvec %lux id %ld\n",
122
		   aip->idoffset, aip->idvec, a.id);
123
		return 0;
124
	}
125
	aip->idvec |= bit;
126
 
127
	/* normalize the vector */
128
	while(aip->idvec&0xffff0001){
129
		aip->idvec >>= 1;
130
		aip->idoffset++;
131
	}
132
	unlock(&aip->idlock);
133
 
134
	/* ticket name and attach name must match */
135
	if(memcmp(in->uname, t.cuid, sizeof(in->uname)) != 0){
136
		print("9p1: names don't match\n");
137
		return 0;
138
	}
139
 
140
	/* copy translated name into input record */
141
	memmove(in->uname, t.suid, sizeof(in->uname));
142
 
143
	/* craft a reply */
144
	a.num = AuthAs;
145
	memmove(a.chal, aip->rchal, CHALLEN);
146
	convA2M9p1(&a, ou->rauth, t.key);
147
 
148
	return 1;
149
}
150
 
151
/*
152
 * buggery to give false qid for
153
 * the top 2 levels of the dump fs
154
 */
155
void
156
mkqid(Qid* qid, Dentry *d, int buggery)
157
{
158
	int c;
159
 
160
	if(buggery && d->qid.path == (QPDIR|QPROOT)){
161
		c = d->name[0];
162
		if(isascii(c) && isdigit(c)){
163
			qid->path = 3;
164
			qid->vers = d->qid.version;
165
			qid->type = QTDIR;
166
 
167
			c = (c-'0')*10 + (d->name[1]-'0');
168
			if(c >= 1 && c <= 12)
169
				qid->path = 4;
170
			return;
171
		}
172
	}
173
 
174
	mkqid9p2(qid, &d->qid, d->mode);
175
}
176
 
177
int
178
mkqidcmp(Qid* qid, Dentry *d)
179
{
180
	Qid tmp;
181
 
182
	mkqid(&tmp, d, 1);
183
	if(qid->path == tmp.path && qid->type == tmp.type)
184
		return 0;
185
	return Eqid;
186
}
187
 
188
static void
189
f_attach(Chan *cp, Fcall *in, Fcall *ou)
190
{
191
	Iobuf *p;
192
	Dentry *d;
193
	File *f;
194
	int u;
195
	Filsys *fs;
196
	Off raddr;
197
 
198
	if(CHAT(cp)) {
199
		print("c_attach %d\n", cp->chan);
200
		print("\tfid = %d\n", in->fid);
201
		print("\tuid = %s\n", in->uname);
202
		print("\targ = %s\n", in->aname);
203
	}
204
 
205
	ou->qid = QID9P1(0,0);
206
	ou->fid = in->fid;
207
	if(!in->aname[0])	/* default */
208
		strncpy(in->aname, "main", sizeof(in->aname));
209
	p = 0;
210
	f = filep(cp, in->fid, 1);
211
	if(!f) {
212
		ou->err = Efid;
213
		goto out;
214
	}
215
 
216
	u = -1;
217
	if(cp != cons.chan) {
218
		if(noattach && strcmp(in->uname, "none")) {
219
			ou->err = Enoattach;
220
			goto out;
221
		}
222
		if(authorize(cp, in, ou) == 0 || strcmp(in->uname, "adm") == 0) {
223
			ou->err = Eauth;
224
			goto out;
225
		}
226
		u = strtouid(in->uname);
227
		if(u < 0) {
228
			ou->err = Ebadu;
229
			goto out;
230
		}
231
	}
232
	f->uid = u;
233
 
234
	fs = fsstr(in->aname);
235
	if(fs == 0) {
236
		ou->err = Ebadspc;
237
		goto out;
238
	}
239
	raddr = getraddr(fs->dev);
240
	p = getbuf(fs->dev, raddr, Brd);
241
	d = getdir(p, 0);
242
	if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) {
243
		ou->err = Ealloc;
244
		goto out;
245
	}
246
	if (iaccess(f, d, DEXEC) ||
247
	    f->uid == 0 && fs->dev->type == Devro) {
248
		/*
249
		 * 'none' not allowed on dump
250
		 */
251
		ou->err = Eaccess;
252
		goto out;
253
	}
254
	accessdir(p, d, FREAD, f->uid);
255
	mkqid(&f->qid, d, 1);
256
	f->fs = fs;
257
	f->addr = raddr;
258
	f->slot = 0;
259
	f->open = 0;
260
	freewp(f->wpath);
261
	f->wpath = 0;
262
 
263
	mkqid9p1(&ou->qid, &f->qid);
264
 
265
	strncpy(cp->whoname, in->uname, sizeof(cp->whoname));
266
	cp->whotime = time(nil);
267
	if(cons.flags & attachflag)
268
		print("9p1: attach %s %T to \"%s\" C%d\n",
269
			cp->whoname, cp->whotime, fs->name, cp->chan);
270
 
271
out:
272
	if((cons.flags & attachflag) && ou->err)
273
		print("9p1: attach %s %T SUCK EGGS --- %s\n",
274
			in->uname, time(nil), errstr9p[ou->err]);
275
	if(p)
276
		putbuf(p);
277
	if(f) {
278
		qunlock(f);
279
		if(ou->err)
280
			freefp(f);
281
	}
282
}
283
 
284
static void
285
f_clone(Chan *cp, Fcall *in, Fcall *ou)
286
{
287
	File *f1, *f2;
288
	Wpath *p;
289
	int fid, fid1;
290
 
291
	if(CHAT(cp)) {
292
		print("c_clone %d\n", cp->chan);
293
		print("\told fid = %d\n", in->fid);
294
		print("\tnew fid = %d\n", in->newfid);
295
	}
296
 
297
	fid = in->fid;
298
	fid1 = in->newfid;
299
 
300
	f1 = 0;
301
	f2 = 0;
302
	if(fid < fid1) {
303
		f1 = filep(cp, fid, 0);
304
		f2 = filep(cp, fid1, 1);
305
	} else
306
	if(fid1 < fid) {
307
		f2 = filep(cp, fid1, 1);
308
		f1 = filep(cp, fid, 0);
309
	}
310
	if(!f1 || !f2) {
311
		ou->err = Efid;
312
		goto out;
313
	}
314
 
315
 
316
	f2->fs = f1->fs;
317
	f2->addr = f1->addr;
318
	f2->open = f1->open & ~FREMOV;
319
	f2->uid = f1->uid;
320
	f2->slot = f1->slot;
321
	f2->qid = f1->qid;
322
 
323
	freewp(f2->wpath);
324
	lock(&wpathlock);
325
	f2->wpath = f1->wpath;
326
	for(p = f2->wpath; p; p = p->up)
327
		p->refs++;
328
	unlock(&wpathlock);
329
 
330
out:
331
	ou->fid = fid;
332
	if(f1)
333
		qunlock(f1);
334
	if(f2) {
335
		qunlock(f2);
336
		if(ou->err)
337
			freefp(f2);
338
	}
339
}
340
 
341
static void
342
f_walk(Chan *cp, Fcall *in, Fcall *ou)
343
{
344
	Iobuf *p, *p1;
345
	Dentry *d, *d1;
346
	File *f;
347
	Wpath *w;
348
	int slot;
349
	Off addr, qpath;
350
 
351
	if(CHAT(cp)) {
352
		print("c_walk %d\n", cp->chan);
353
		print("\tfid = %d\n", in->fid);
354
		print("\tname = %s\n", in->name);
355
	}
356
 
357
	ou->fid = in->fid;
358
	ou->qid = QID9P1(0,0);
359
	p = 0;
360
	f = filep(cp, in->fid, 0);
361
	if(!f) {
362
		ou->err = Efid;
363
		goto out;
364
	}
365
	p = getbuf(f->fs->dev, f->addr, Brd);
366
	d = getdir(p, f->slot);
367
	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
368
		ou->err = Ealloc;
369
		goto out;
370
	}
371
	if(!(d->mode & DDIR)) {
372
		ou->err = Edir1;
373
		goto out;
374
	}
375
	if(ou->err = mkqidcmp(&f->qid, d))
376
		goto out;
377
	if(cp != cons.chan && iaccess(f, d, DEXEC)) {
378
		ou->err = Eaccess;
379
		goto out;
380
	}
381
	accessdir(p, d, FREAD, f->uid);
382
	if(strcmp(in->name, ".") == 0)
383
		goto setdot;
384
	if(strcmp(in->name, "..") == 0) {
385
		if(f->wpath == 0)
386
			goto setdot;
387
		putbuf(p);
388
		p = 0;
389
		addr = f->wpath->addr;
390
		slot = f->wpath->slot;
391
		p1 = getbuf(f->fs->dev, addr, Brd);
392
		d1 = getdir(p1, slot);
393
		if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
394
			if(p1)
395
				putbuf(p1);
396
			ou->err = Ephase;
397
			goto out;
398
		}
399
		lock(&wpathlock);
400
		f->wpath->refs--;
401
		f->wpath = f->wpath->up;
402
		unlock(&wpathlock);
403
		goto found;
404
	}
405
	for(addr=0;; addr++) {
406
		if(p == 0) {
407
			p = getbuf(f->fs->dev, f->addr, Brd);
408
			d = getdir(p, f->slot);
409
			if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
410
				ou->err = Ealloc;
411
				goto out;
412
			}
413
		}
414
		qpath = d->qid.path;
415
		p1 = dnodebuf1(p, d, addr, 0, f->uid);
416
		p = 0;
417
		if(!p1 || checktag(p1, Tdir, qpath) ) {
418
			if(p1)
419
				putbuf(p1);
420
			ou->err = Eentry;
421
			goto out;
422
		}
423
		for(slot=0; slot<DIRPERBUF; slot++) {
424
			d1 = getdir(p1, slot);
425
			if(!(d1->mode & DALLOC))
426
				continue;
427
			if(strncmp(in->name, d1->name, sizeof(in->name)) != 0)
428
				continue;
429
			/*
430
			 * update walk path
431
			 */
432
			w = newwp();
433
			if(!w) {
434
				ou->err = Ewalk;
435
				putbuf(p1);
436
				goto out;
437
			}
438
			w->addr = f->addr;
439
			w->slot = f->slot;
440
			w->up = f->wpath;
441
			f->wpath = w;
442
			slot += DIRPERBUF*addr;
443
			goto found;
444
		}
445
		putbuf(p1);
446
	}
447
 
448
found:
449
	f->addr = p1->addr;
450
	mkqid(&f->qid, d1, 1);
451
	putbuf(p1);
452
	f->slot = slot;
453
 
454
setdot:
455
	mkqid9p1(&ou->qid, &f->qid);
456
	f->open = 0;
457
 
458
out:
459
	if(p)
460
		putbuf(p);
461
	if(f)
462
		qunlock(f);
463
}
464
 
465
static void
466
f_open(Chan *cp, Fcall *in, Fcall *ou)
467
{
468
	Iobuf *p;
469
	Dentry *d;
470
	File *f;
471
	Tlock *t;
472
	Qid qid;
473
	int ro, fmod, wok;
474
 
475
	if(CHAT(cp)) {
476
		print("c_open %d\n", cp->chan);
477
		print("\tfid = %d\n", in->fid);
478
		print("\tmode = %o\n", in->mode);
479
	}
480
 
481
	wok = 0;
482
	if(cp == cons.chan || writeallow)
483
		wok = 1;
484
 
485
	p = 0;
486
	f = filep(cp, in->fid, 0);
487
	if(!f) {
488
		ou->err = Efid;
489
		goto out;
490
	}
491
 
492
	/*
493
	 * if remove on close, check access here
494
	 */
495
	ro = f->fs->dev->type == Devro;
496
	if(in->mode & ORCLOSE) {
497
		if(ro) {
498
			ou->err = Eronly;
499
			goto out;
500
		}
501
		/*
502
		 * check on parent directory of file to be deleted
503
		 */
504
		if(f->wpath == 0 || f->wpath->addr == f->addr) {
505
			ou->err = Ephase;
506
			goto out;
507
		}
508
		p = getbuf(f->fs->dev, f->wpath->addr, Brd);
509
		d = getdir(p, f->wpath->slot);
510
		if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
511
			ou->err = Ephase;
512
			goto out;
513
		}
514
		if(iaccess(f, d, DWRITE)) {
515
			ou->err = Eaccess;
516
			goto out;
517
		}
518
		putbuf(p);
519
	}
520
	p = getbuf(f->fs->dev, f->addr, Brd);
521
	d = getdir(p, f->slot);
522
	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
523
		ou->err = Ealloc;
524
		goto out;
525
	}
526
	if(ou->err = mkqidcmp(&f->qid, d))
527
		goto out;
528
	mkqid(&qid, d, 1);
529
	switch(in->mode & 7) {
530
 
531
	case OREAD:
532
		if(iaccess(f, d, DREAD) && !wok)
533
			goto badaccess;
534
		fmod = FREAD;
535
		break;
536
 
537
	case OWRITE:
538
		if((d->mode & DDIR) ||
539
		   (iaccess(f, d, DWRITE) && !wok))
540
			goto badaccess;
541
		if(ro) {
542
			ou->err = Eronly;
543
			goto out;
544
		}
545
		fmod = FWRITE;
546
		break;
547
 
548
	case ORDWR:
549
		if((d->mode & DDIR) ||
550
		   (iaccess(f, d, DREAD) && !wok) ||
551
		   (iaccess(f, d, DWRITE) && !wok))
552
			goto badaccess;
553
		if(ro) {
554
			ou->err = Eronly;
555
			goto out;
556
		}
557
		fmod = FREAD+FWRITE;
558
		break;
559
 
560
	case OEXEC:
561
		if((d->mode & DDIR) ||
562
		   (iaccess(f, d, DEXEC) && !wok))
563
			goto badaccess;
564
		fmod = FREAD;
565
		break;
566
 
567
	default:
568
		ou->err = Emode;
569
		goto out;
570
	}
571
	if(in->mode & OTRUNC) {
572
		if((d->mode & DDIR) ||
573
		   (iaccess(f, d, DWRITE) && !wok))
574
			goto badaccess;
575
		if(ro) {
576
			ou->err = Eronly;
577
			goto out;
578
		}
579
	}
580
	t = 0;
581
	if(d->mode & DLOCK) {
582
		t = tlocked(p, d);
583
		if(t == nil) {
584
			ou->err = Elocked;
585
			goto out;
586
		}
587
	}
588
	if(in->mode & ORCLOSE)
589
		fmod |= FREMOV;
590
	f->open = fmod;
591
	if(in->mode & OTRUNC)
592
		if(!(d->mode & DAPND)) {
593
			dtrunc(p, d, f->uid);
594
			qid.vers = d->qid.version;
595
		}
596
	f->tlock = t;
597
	if(t)
598
		t->file = f;
599
	f->lastra = 1;
600
	mkqid9p1(&ou->qid, &qid);
601
	goto out;
602
 
603
badaccess:
604
	ou->err = Eaccess;
605
	f->open = 0;
606
 
607
out:
608
	if(p)
609
		putbuf(p);
610
	if(f)
611
		qunlock(f);
612
	ou->fid = in->fid;
613
}
614
 
615
static void
616
f_create(Chan *cp, Fcall *in, Fcall *ou)
617
{
618
	Iobuf *p, *p1;
619
	Dentry *d, *d1;
620
	File *f;
621
	int slot, slot1, fmod, wok;
622
	Off addr, addr1, path;
623
	Qid qid;
624
	Tlock *t;
625
	Wpath *w;
626
 
627
	if(CHAT(cp)) {
628
		print("c_create %d\n", cp->chan);
629
		print("\tfid = %d\n", in->fid);
630
		print("\tname = %s\n", in->name);
631
		print("\tperm = %lx+%lo\n", (in->perm>>28)&0xf,
632
				in->perm&0777);
633
		print("\tmode = %o\n", in->mode);
634
	}
635
 
636
	wok = 0;
637
	if(cp == cons.chan || writeallow)
638
		wok = 1;
639
 
640
	p = 0;
641
	f = filep(cp, in->fid, 0);
642
	if(!f) {
643
		ou->err = Efid;
644
		goto out;
645
	}
646
	if(f->fs->dev->type == Devro) {
647
		ou->err = Eronly;
648
		goto out;
649
	}
650
 
651
	p = getbuf(f->fs->dev, f->addr, Brd);
652
	d = getdir(p, f->slot);
653
	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
654
		ou->err = Ealloc;
655
		goto out;
656
	}
657
	if(ou->err = mkqidcmp(&f->qid, d))
658
		goto out;
659
	if(!(d->mode & DDIR)) {
660
		ou->err = Edir2;
661
		goto out;
662
	}
663
	if(iaccess(f, d, DWRITE) && !wok) {
664
		ou->err = Eaccess;
665
		goto out;
666
	}
667
	accessdir(p, d, FREAD, f->uid);
668
	if(!strncmp(in->name, ".", sizeof(in->name)) ||
669
	   !strncmp(in->name, "..", sizeof(in->name))) {
670
		ou->err = Edot;
671
		goto out;
672
	}
673
	if(checkname(in->name)) {
674
		ou->err = Ename;
675
		goto out;
676
	}
677
	addr1 = 0;
678
	slot1 = 0;	/* set */
679
	for(addr=0;; addr++) {
680
		p1 = dnodebuf(p, d, addr, 0, f->uid);
681
		if(!p1) {
682
			if(addr1)
683
				break;
684
			p1 = dnodebuf(p, d, addr, Tdir, f->uid);
685
		}
686
		if(p1 == 0) {
687
			ou->err = Efull;
688
			goto out;
689
		}
690
		if(checktag(p1, Tdir, d->qid.path)) {
691
			putbuf(p1);
692
			goto phase;
693
		}
694
		for(slot=0; slot<DIRPERBUF; slot++) {
695
			d1 = getdir(p1, slot);
696
			if(!(d1->mode & DALLOC)) {
697
				if(!addr1) {
698
					addr1 = p1->addr;
699
					slot1 = slot + addr*DIRPERBUF;
700
				}
701
				continue;
702
			}
703
			if(!strncmp(in->name, d1->name, sizeof(in->name))) {
704
				putbuf(p1);
705
				ou->err = Eexist;
706
				goto out;
707
			}
708
		}
709
		putbuf(p1);
710
	}
711
	switch(in->mode & 7) {
712
	case OEXEC:
713
	case OREAD:		/* seems only useful to make directories */
714
		fmod = FREAD;
715
		break;
716
 
717
	case OWRITE:
718
		fmod = FWRITE;
719
		break;
720
 
721
	case ORDWR:
722
		fmod = FREAD+FWRITE;
723
		break;
724
 
725
	default:
726
		ou->err = Emode;
727
		goto out;
728
	}
729
	if(in->perm & PDIR)
730
		if((in->mode & OTRUNC) || (in->perm & PAPND) || (fmod & FWRITE))
731
			goto badaccess;
732
	/*
733
	 * do it
734
	 */
735
	path = qidpathgen(f->fs->dev);
736
	p1 = getbuf(f->fs->dev, addr1, Brd|Bimm|Bmod);
737
	d1 = getdir(p1, slot1);
738
	if(!d1 || checktag(p1, Tdir, d->qid.path)) {
739
		if(p1)
740
			putbuf(p1);
741
		goto phase;
742
	}
743
	if(d1->mode & DALLOC) {
744
		putbuf(p1);
745
		goto phase;
746
	}
747
 
748
	strncpy(d1->name, in->name, sizeof(in->name));
749
	if(cp == cons.chan) {
750
		d1->uid = cons.uid;
751
		d1->gid = cons.gid;
752
	} else {
753
		d1->uid = f->uid;
754
		d1->gid = d->gid;
755
		in->perm &= d->mode | ~0666;
756
		if(in->perm & PDIR)
757
			in->perm &= d->mode | ~0777;
758
	}
759
	d1->qid.path = path;
760
	d1->qid.version = 0;
761
	d1->mode = DALLOC | (in->perm & 0777);
762
	if(in->perm & PDIR) {
763
		d1->mode |= DDIR;
764
		d1->qid.path |= QPDIR;
765
	}
766
	if(in->perm & PAPND)
767
		d1->mode |= DAPND;
768
	t = 0;
769
	if(in->perm & PLOCK) {
770
		d1->mode |= DLOCK;
771
		t = tlocked(p1, d1);
772
		/* if nil, out of tlock structures */
773
	}
774
	accessdir(p1, d1, FWRITE, f->uid);
775
	mkqid(&qid, d1, 0);
776
	putbuf(p1);
777
	accessdir(p, d, FWRITE, f->uid);
778
 
779
	/*
780
	 * do a walk to new directory entry
781
	 */
782
	w = newwp();
783
	if(!w) {
784
		ou->err = Ewalk;
785
		goto out;
786
	}
787
	w->addr = f->addr;
788
	w->slot = f->slot;
789
	w->up = f->wpath;
790
	f->wpath = w;
791
	f->qid = qid;
792
	f->tlock = t;
793
	if(t)
794
		t->file = f;
795
	f->lastra = 1;
796
	if(in->mode & ORCLOSE)
797
		fmod |= FREMOV;
798
	f->open = fmod;
799
	f->addr = addr1;
800
	f->slot = slot1;
801
	mkqid9p1(&ou->qid, &qid);
802
	goto out;
803
 
804
badaccess:
805
	ou->err = Eaccess;
806
	goto out;
807
 
808
phase:
809
	ou->err = Ephase;
810
 
811
out:
812
	if(p)
813
		putbuf(p);
814
	if(f)
815
		qunlock(f);
816
	ou->fid = in->fid;
817
}
818
 
819
static void
820
f_read(Chan *cp, Fcall *in, Fcall *ou)
821
{
822
	Iobuf *p, *p1;
823
	File *f;
824
	Dentry *d, *d1;
825
	Tlock *t;
826
	Off addr, offset;
827
	Timet tim;
828
	int nread, count, n, o, slot;
829
 
830
	if(CHAT(cp)) {
831
		print("c_read %d\n", cp->chan);
832
		print("\tfid = %d\n", in->fid);
833
		print("\toffset = %lld\n", (Wideoff)in->offset);
834
		print("\tcount = %ld\n", in->count);
835
	}
836
 
837
	p = 0;
838
	count = in->count;
839
	offset = in->offset;
840
	nread = 0;
841
	f = filep(cp, in->fid, 0);
842
	if(!f) {
843
		ou->err = Efid;
844
		goto out;
845
	}
846
	if(!(f->open & FREAD)) {
847
		ou->err = Eopen;
848
		goto out;
849
	}
850
	if(count < 0 || count > MAXDAT) {
851
		ou->err = Ecount;
852
		goto out;
853
	}
854
	if(offset < 0) {
855
		ou->err = Eoffset;
856
		goto out;
857
	}
858
	p = getbuf(f->fs->dev, f->addr, Brd);
859
	d = getdir(p, f->slot);
860
	if(!d || !(d->mode & DALLOC)) {
861
		ou->err = Ealloc;
862
		goto out;
863
	}
864
	if(ou->err = mkqidcmp(&f->qid, d))
865
		goto out;
866
	if(t = f->tlock) {
867
		tim = toytime();
868
		if(t->time < tim || t->file != f) {
869
			ou->err = Ebroken;
870
			goto out;
871
		}
872
		/* renew the lock */
873
		t->time = tim + TLOCK;
874
	}
875
	accessdir(p, d, FREAD, f->uid);
876
	if(d->mode & DDIR) {
877
		addr = 0;
878
		goto dread;
879
	}
880
 
881
	/* XXXX terrible hack to get at raw data XXXX */
882
	if(rawreadok && strncmp(d->name, "--raw--", 7) == 0) {
883
		Device *dev;
884
		Devsize boff, bsize;
885
 
886
		dev = p->dev;
887
		putbuf(p);
888
		p = 0;
889
 
890
		boff = number(d->name + 7, 0, 10) * 100000;
891
		if(boff < 0)
892
			boff = 0;
893
		if(boff > devsize(dev))
894
			boff = devsize(dev);
895
		bsize = devsize(dev) - boff;
896
 
897
		if(offset+count >= 100000*RBUFSIZE)
898
			count = 100000*RBUFSIZE - offset;
899
 
900
		if((offset+count)/RBUFSIZE >= bsize)
901
			/* will not overflow */
902
			count = bsize*RBUFSIZE - offset;
903
 
904
		while(count > 0) {
905
			addr = offset / RBUFSIZE;
906
			addr += boff;
907
			o = offset % RBUFSIZE;
908
			n = RBUFSIZE - o;
909
			if(n > count)
910
				n = count;
911
 
912
			p1 = getbuf(dev, addr, Brd);
913
			if(p1) {
914
				memmove(ou->data+nread, p1->iobuf+o, n);
915
				putbuf(p1);
916
			} else
917
				memset(ou->data+nread, 0, n);
918
			count -= n;
919
			nread += n;
920
			offset += n;
921
		}
922
		goto out;
923
	}
924
 
925
	if(offset+count > d->size)
926
		count = d->size - offset;
927
	while(count > 0) {
928
		if(p == 0) {
929
			p = getbuf(f->fs->dev, f->addr, Brd);
930
			d = getdir(p, f->slot);
931
			if(!d || !(d->mode & DALLOC)) {
932
				ou->err = Ealloc;
933
				goto out;
934
			}
935
		}
936
		addr = offset / BUFSIZE;
937
		f->lastra = dbufread(p, d, addr, f->lastra, f->uid);
938
		o = offset % BUFSIZE;
939
		n = BUFSIZE - o;
940
		if(n > count)
941
			n = count;
942
		p1 = dnodebuf1(p, d, addr, 0, f->uid);
943
		p = 0;
944
		if(p1) {
945
			if(checktag(p1, Tfile, QPNONE)) {
946
				ou->err = Ephase;
947
				putbuf(p1);
948
				goto out;
949
			}
950
			memmove(ou->data+nread, p1->iobuf+o, n);
951
			putbuf(p1);
952
		} else
953
			memset(ou->data+nread, 0, n);
954
		count -= n;
955
		nread += n;
956
		offset += n;
957
	}
958
	goto out;
959
 
960
dread:
961
	for (;;) {
962
		if(p == 0) {
963
			p = getbuf(f->fs->dev, f->addr, Brd);
964
			d = getdir(p, f->slot);
965
			if(!d || !(d->mode & DALLOC)) {
966
				ou->err = Ealloc;
967
				goto out;
968
			}
969
		}
970
		p1 = dnodebuf1(p, d, addr, 0, f->uid);
971
		p = 0;
972
		if(!p1)
973
			goto out;
974
		if(checktag(p1, Tdir, QPNONE)) {
975
			ou->err = Ephase;
976
			putbuf(p1);
977
			goto out;
978
		}
979
		n = DIRREC;
980
		for(slot=0; slot<DIRPERBUF; slot++) {
981
			d1 = getdir(p1, slot);
982
			if(!(d1->mode & DALLOC))
983
				continue;
984
			if(offset >= n) {
985
				offset -= n;
986
				continue;
987
			}
988
			if(count < n) {
989
				putbuf(p1);
990
				goto out;
991
			}
992
			if(convD2M9p1(d1, ou->data+nread) != n)
993
				print("9p1: dirread convD2M1990\n");
994
			nread += n;
995
			count -= n;
996
		}
997
		putbuf(p1);
998
		addr++;
999
	}
1000
out:
1001
	count = in->count - nread;
1002
	if(count > 0)
1003
		memset(ou->data+nread, 0, count);
1004
	if(p)
1005
		putbuf(p);
1006
	if(f)
1007
		qunlock(f);
1008
	ou->fid = in->fid;
1009
	ou->count = nread;
1010
	if(CHAT(cp))
1011
		print("\tnread = %d\n", nread);
1012
}
1013
 
1014
static void
1015
f_write(Chan *cp, Fcall *in, Fcall *ou)
1016
{
1017
	Iobuf *p, *p1;
1018
	Dentry *d;
1019
	File *f;
1020
	Tlock *t;
1021
	Off offset, addr, qpath;
1022
	Timet tim;
1023
	int count, nwrite, o, n;
1024
 
1025
	if(CHAT(cp)) {
1026
		print("c_write %d\n", cp->chan);
1027
		print("\tfid = %d\n", in->fid);
1028
		print("\toffset = %lld\n", (Wideoff)in->offset);
1029
		print("\tcount = %ld\n", in->count);
1030
	}
1031
 
1032
	offset = in->offset;
1033
	count = in->count;
1034
	nwrite = 0;
1035
	p = 0;
1036
	f = filep(cp, in->fid, 0);
1037
	if(!f) {
1038
		ou->err = Efid;
1039
		goto out;
1040
	}
1041
	if(!(f->open & FWRITE)) {
1042
		ou->err = Eopen;
1043
		goto out;
1044
	}
1045
	if(f->fs->dev->type == Devro) {
1046
		ou->err = Eronly;
1047
		goto out;
1048
	}
1049
	if(count < 0 || count > MAXDAT) {
1050
		ou->err = Ecount;
1051
		goto out;
1052
	}
1053
	if(offset < 0) {
1054
		ou->err = Eoffset;
1055
		goto out;
1056
	}
1057
	p = getbuf(f->fs->dev, f->addr, Brd|Bmod);
1058
	d = getdir(p, f->slot);
1059
	if(!d || !(d->mode & DALLOC)) {
1060
		ou->err = Ealloc;
1061
		goto out;
1062
	}
1063
	if(ou->err = mkqidcmp(&f->qid, d))
1064
		goto out;
1065
	if(t = f->tlock) {
1066
		tim = toytime();
1067
		if(t->time < tim || t->file != f) {
1068
			ou->err = Ebroken;
1069
			goto out;
1070
		}
1071
		/* renew the lock */
1072
		t->time = tim + TLOCK;
1073
	}
1074
	accessdir(p, d, FWRITE, f->uid);
1075
	if(d->mode & DAPND)
1076
		offset = d->size;
1077
	if(offset+count > d->size)
1078
		d->size = offset+count;
1079
	while(count > 0) {
1080
		if(p == 0) {
1081
			p = getbuf(f->fs->dev, f->addr, Brd|Bmod);
1082
			d = getdir(p, f->slot);
1083
			if(!d || !(d->mode & DALLOC)) {
1084
				ou->err = Ealloc;
1085
				goto out;
1086
			}
1087
		}
1088
		addr = offset / BUFSIZE;
1089
		o = offset % BUFSIZE;
1090
		n = BUFSIZE - o;
1091
		if(n > count)
1092
			n = count;
1093
		qpath = d->qid.path;
1094
		p1 = dnodebuf1(p, d, addr, Tfile, f->uid);
1095
		p = 0;
1096
		if(p1 == 0) {
1097
			ou->err = Efull;
1098
			goto out;
1099
		}
1100
		if(checktag(p1, Tfile, qpath)) {
1101
			putbuf(p1);
1102
			ou->err = Ephase;
1103
			goto out;
1104
		}
1105
		memmove(p1->iobuf+o, in->data+nwrite, n);
1106
		p1->flags |= Bmod;
1107
		putbuf(p1);
1108
		count -= n;
1109
		nwrite += n;
1110
		offset += n;
1111
	}
1112
	if(CHAT(cp))
1113
		print("\tnwrite = %d\n", nwrite);
1114
 
1115
out:
1116
	if(p)
1117
		putbuf(p);
1118
	if(f)
1119
		qunlock(f);
1120
	ou->fid = in->fid;
1121
	ou->count = nwrite;
1122
}
1123
 
1124
int
1125
doremove(File *f, int wok)
1126
{
1127
	Iobuf *p, *p1;
1128
	Dentry *d, *d1;
1129
	Off addr;
1130
	int slot, err;
1131
 
1132
	p = 0;
1133
	p1 = 0;
1134
	if(f->fs->dev->type == Devro) {
1135
		err = Eronly;
1136
		goto out;
1137
	}
1138
	/*
1139
	 * check on parent directory of file to be deleted
1140
	 */
1141
	if(f->wpath == 0 || f->wpath->addr == f->addr) {
1142
		err = Ephase;
1143
		goto out;
1144
	}
1145
	p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
1146
	d1 = getdir(p1, f->wpath->slot);
1147
	if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
1148
		err = Ephase;
1149
		goto out;
1150
	}
1151
	if(iaccess(f, d1, DWRITE) && !wok) {
1152
		err = Eaccess;
1153
		goto out;
1154
	}
1155
	accessdir(p1, d1, FWRITE, f->uid);
1156
	putbuf(p1);
1157
	p1 = 0;
1158
 
1159
	/*
1160
	 * check on file to be deleted
1161
	 */
1162
	p = getbuf(f->fs->dev, f->addr, Brd);
1163
	d = getdir(p, f->slot);
1164
	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1165
		err = Ealloc;
1166
		goto out;
1167
	}
1168
	if(err = mkqidcmp(&f->qid, d))
1169
		goto out;
1170
 
1171
	/*
1172
	 * if deleting a directory, make sure it is empty
1173
	 */
1174
	if((d->mode & DDIR))
1175
	for(addr=0;; addr++) {
1176
		p1 = dnodebuf(p, d, addr, 0, f->uid);
1177
		if(!p1)
1178
			break;
1179
		if(checktag(p1, Tdir, d->qid.path)) {
1180
			err = Ephase;
1181
			goto out;
1182
		}
1183
		for(slot=0; slot<DIRPERBUF; slot++) {
1184
			d1 = getdir(p1, slot);
1185
			if(!(d1->mode & DALLOC))
1186
				continue;
1187
			err = Eempty;
1188
			goto out;
1189
		}
1190
		putbuf(p1);
1191
	}
1192
 
1193
	/*
1194
	 * do it
1195
	 */
1196
	dtrunc(p, d, f->uid);
1197
	memset(d, 0, sizeof(Dentry));
1198
	settag(p, Tdir, QPNONE);
1199
 
1200
out:
1201
	if(p1)
1202
		putbuf(p1);
1203
	if(p)
1204
		putbuf(p);
1205
	return err;
1206
}
1207
 
1208
static int
1209
doclunk(File* f, int remove, int wok)
1210
{
1211
	Tlock *t;
1212
	int err;
1213
 
1214
	err = 0;
1215
	if(t = f->tlock) {
1216
		if(t->file == f)
1217
			t->time = 0;	/* free the lock */
1218
		f->tlock = 0;
1219
	}
1220
	if(remove)
1221
		err = doremove(f, wok);
1222
	f->open = 0;
1223
	freewp(f->wpath);
1224
	freefp(f);
1225
 
1226
	return err;
1227
}
1228
 
1229
static void
1230
f_clunk(Chan *cp, Fcall *in, Fcall *ou)
1231
{
1232
	File *f;
1233
 
1234
	if(CHAT(cp)) {
1235
		print("c_clunk %d\n", cp->chan);
1236
		print("\tfid = %d\n", in->fid);
1237
	}
1238
 
1239
	f = filep(cp, in->fid, 0);
1240
	if(!f)
1241
		ou->err = Efid;
1242
	else {
1243
		doclunk(f, f->open & FREMOV, 0);
1244
		qunlock(f);
1245
	}
1246
	ou->fid = in->fid;
1247
}
1248
 
1249
static void
1250
f_remove(Chan *cp, Fcall *in, Fcall *ou)
1251
{
1252
	File *f;
1253
 
1254
	if(CHAT(cp)) {
1255
		print("c_remove %d\n", cp->chan);
1256
		print("\tfid = %d\n", in->fid);
1257
	}
1258
 
1259
	f = filep(cp, in->fid, 0);
1260
	if(!f)
1261
		ou->err = Efid;
1262
	else {
1263
		ou->err = doclunk(f, 1, cp==cons.chan);
1264
		qunlock(f);
1265
	}
1266
	ou->fid = in->fid;
1267
}
1268
 
1269
static void
1270
f_stat(Chan *cp, Fcall *in, Fcall *ou)
1271
{
1272
	Iobuf *p;
1273
	Dentry *d;
1274
	File *f;
1275
 
1276
	if(CHAT(cp)) {
1277
		print("c_stat %d\n", cp->chan);
1278
		print("\tfid = %d\n", in->fid);
1279
	}
1280
 
1281
	p = 0;
1282
	memset(ou->stat, 0, sizeof(ou->stat));
1283
	f = filep(cp, in->fid, 0);
1284
	if(!f) {
1285
		ou->err = Efid;
1286
		goto out;
1287
	}
1288
	p = getbuf(f->fs->dev, f->addr, Brd);
1289
	d = getdir(p, f->slot);
1290
	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1291
		ou->err = Ealloc;
1292
		goto out;
1293
	}
1294
	if(ou->err = mkqidcmp(&f->qid, d))
1295
		goto out;
1296
	if(d->qid.path == QPROOT)	/* stat of root gives time */
1297
		d->atime = time(nil);
1298
	if(convD2M9p1(d, ou->stat) != DIRREC)
1299
		print("9p1: stat convD2M\n");
1300
 
1301
out:
1302
	if(p)
1303
		putbuf(p);
1304
	if(f)
1305
		qunlock(f);
1306
	ou->fid = in->fid;
1307
}
1308
 
1309
static void
1310
f_wstat(Chan *cp, Fcall *in, Fcall *ou)
1311
{
1312
	Iobuf *p, *p1;
1313
	Dentry *d, *d1, xd;
1314
	File *f;
1315
	int slot;
1316
	Off addr;
1317
 
1318
	if(CHAT(cp)) {
1319
		print("c_wstat %d\n", cp->chan);
1320
		print("\tfid = %d\n", in->fid);
1321
	}
1322
 
1323
	p = 0;
1324
	p1 = 0;
1325
	d1 = 0;
1326
	f = filep(cp, in->fid, 0);
1327
	if(!f) {
1328
		ou->err = Efid;
1329
		goto out;
1330
	}
1331
	if(f->fs->dev->type == Devro) {
1332
		ou->err = Eronly;
1333
		goto out;
1334
	}
1335
 
1336
	/*
1337
	 * first get parent
1338
	 */
1339
	if(f->wpath) {
1340
		p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
1341
		d1 = getdir(p1, f->wpath->slot);
1342
		if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
1343
			ou->err = Ephase;
1344
			goto out;
1345
		}
1346
	}
1347
 
1348
	p = getbuf(f->fs->dev, f->addr, Brd);
1349
	d = getdir(p, f->slot);
1350
	if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1351
		ou->err = Ealloc;
1352
		goto out;
1353
	}
1354
	if(ou->err = mkqidcmp(&f->qid, d))
1355
		goto out;
1356
 
1357
	convM2D9p1(in->stat, &xd);
1358
	if(CHAT(cp)) {
1359
		print("\td.name = %s\n", xd.name);
1360
		print("\td.uid  = %d\n", xd.uid);
1361
		print("\td.gid  = %d\n", xd.gid);
1362
		print("\td.mode = %o\n", xd.mode);
1363
	}
1364
 
1365
	/*
1366
	 * if user none,
1367
	 * cant do anything
1368
	 */
1369
	if(f->uid == 0) {
1370
		ou->err = Eaccess;
1371
		goto out;
1372
	}
1373
 
1374
	/*
1375
	 * if chown,
1376
	 * must be god
1377
	 */
1378
	if(xd.uid != d->uid && !wstatallow) { /* set to allow chown during boot */
1379
		ou->err = Ewstatu;
1380
		goto out;
1381
	}
1382
 
1383
	/*
1384
	 * if chgroup,
1385
	 * must be either
1386
	 *	a) owner and in new group
1387
	 *	b) leader of both groups
1388
	 */
1389
	if (xd.gid != d->gid &&
1390
	    (!wstatallow && !writeallow &&  /* set to allow chgrp during boot */
1391
	     (d->uid != f->uid || !ingroup(f->uid, xd.gid)) &&
1392
	     (!leadgroup(f->uid, xd.gid) || !leadgroup(f->uid, d->gid)))) {
1393
		ou->err = Ewstatg;
1394
		goto out;
1395
	}
1396
 
1397
	/*
1398
	 * if rename,
1399
	 * must have write permission in parent
1400
	 */
1401
	if (strncmp(d->name, xd.name, sizeof(d->name)) != 0) {
1402
		if (checkname(xd.name) || !d1 ||
1403
		    strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
1404
			ou->err = Ename;
1405
			goto out;
1406
		}
1407
 
1408
		/*
1409
		 * drop entry to prevent lock, then
1410
		 * check that destination name is unique,
1411
		 */
1412
		putbuf(p);
1413
		for(addr=0;; addr++) {
1414
			p = dnodebuf(p1, d1, addr, 0, f->uid);
1415
			if(!p)
1416
				break;
1417
			if(checktag(p, Tdir, d1->qid.path)) {
1418
				putbuf(p);
1419
				continue;
1420
			}
1421
			for(slot=0; slot<DIRPERBUF; slot++) {
1422
				d = getdir(p, slot);
1423
				if(!(d->mode & DALLOC))
1424
					continue;
1425
				if(!strncmp(xd.name, d->name, sizeof(xd.name))) {
1426
					ou->err = Eexist;
1427
					goto out;
1428
				}
1429
			}
1430
			putbuf(p);
1431
		}
1432
 
1433
		/*
1434
		 * reacquire entry
1435
		 */
1436
		p = getbuf(f->fs->dev, f->addr, Brd);
1437
		d = getdir(p, f->slot);
1438
		if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1439
			ou->err = Ephase;
1440
			goto out;
1441
		}
1442
 
1443
		if (!wstatallow && !writeallow && /* set to allow rename during boot */
1444
		    (!d1 || iaccess(f, d1, DWRITE))) {
1445
			ou->err = Eaccess;
1446
			goto out;
1447
		}
1448
	}
1449
 
1450
	/*
1451
	 * if mode/time, either
1452
	 *	a) owner
1453
	 *	b) leader of either group
1454
	 */
1455
	if (d->mtime != xd.mtime ||
1456
	    ((d->mode^xd.mode) & (DAPND|DLOCK|0777)))
1457
		if (!wstatallow &&	/* set to allow chmod during boot */
1458
		    d->uid != f->uid &&
1459
		    !leadgroup(f->uid, xd.gid) &&
1460
		    !leadgroup(f->uid, d->gid)) {
1461
			ou->err = Ewstatu;
1462
			goto out;
1463
		}
1464
	d->mtime = xd.mtime;
1465
	d->uid = xd.uid;
1466
	d->gid = xd.gid;
1467
	d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
1468
 
1469
	strncpy(d->name, xd.name, sizeof(d->name));
1470
	accessdir(p, d, FREAD, f->uid);
1471
 
1472
out:
1473
	if(p)
1474
		putbuf(p);
1475
	if(p1)
1476
		putbuf(p1);
1477
	if(f)
1478
		qunlock(f);
1479
	ou->fid = in->fid;
1480
}
1481
 
1482
static void
1483
f_clwalk(Chan *cp, Fcall *in, Fcall *ou)
1484
{
1485
	int er, fid;
1486
 
1487
	if(CHAT(cp))
1488
		print("c_clwalk macro\n");
1489
 
1490
	f_clone(cp, in, ou);		/* sets tag, fid */
1491
	if(ou->err)
1492
		return;
1493
	fid = in->fid;
1494
	in->fid = in->newfid;
1495
	f_walk(cp, in, ou);		/* sets tag, fid, qid */
1496
	er = ou->err;
1497
	if(er == Eentry) {
1498
		/*
1499
		 * if error is "no entry"
1500
		 * return non error and fid
1501
		 */
1502
		ou->err = 0;
1503
		f_clunk(cp, in, ou);	/* sets tag, fid */
1504
		ou->err = 0;
1505
		ou->fid = fid;
1506
		if(CHAT(cp))
1507
			print("\terror: %s\n", errstr9p[er]);
1508
	} else if(er) {
1509
		/*
1510
		 * if any other error
1511
		 * return an error
1512
		 */
1513
		ou->err = 0;
1514
		f_clunk(cp, in, ou);	/* sets tag, fid */
1515
		ou->err = er;
1516
	}
1517
	/*
1518
	 * non error
1519
	 * return newfid
1520
	 */
1521
}
1522
 
1523
void (*call9p1[MAXSYSCALL])(Chan*, Fcall*, Fcall*) =
1524
{
1525
	[Tnop]		f_nop,
1526
	[Tosession]	f_session,
1527
	[Tsession]	f_session,
1528
	[Tflush]	f_flush,
1529
	[Toattach]	f_attach,
1530
	[Tattach]	f_attach,
1531
	[Tclone]	f_clone,
1532
	[Twalk]		f_walk,
1533
	[Topen]		f_open,
1534
	[Tcreate]	f_create,
1535
	[Tread]		f_read,
1536
	[Twrite]	f_write,
1537
	[Tclunk]	f_clunk,
1538
	[Tremove]	f_remove,
1539
	[Tstat]		f_stat,
1540
	[Twstat]	f_wstat,
1541
	[Tclwalk]	f_clwalk,
1542
};
1543
 
1544
int
1545
error9p1(Chan* cp, Msgbuf* mb)
1546
{
1547
	Msgbuf *mb1;
1548
 
1549
	print("type=%d count=%d\n", mb->data[0], mb->count);
1550
	print(" %.2x %.2x %.2x %.2x\n",
1551
		mb->data[1]&0xff, mb->data[2]&0xff,
1552
		mb->data[3]&0xff, mb->data[4]&0xff);
1553
	print(" %.2x %.2x %.2x %.2x\n",
1554
		mb->data[5]&0xff, mb->data[6]&0xff,
1555
		mb->data[7]&0xff, mb->data[8]&0xff);
1556
	print(" %.2x %.2x %.2x %.2x\n",
1557
		mb->data[9]&0xff, mb->data[10]&0xff,
1558
		mb->data[11]&0xff, mb->data[12]&0xff);
1559
 
1560
	mb1 = mballoc(3, cp, Mbreply4);
1561
	mb1->data[0] = Rnop;	/* your nop was ok */
1562
	mb1->data[1] = ~0;
1563
	mb1->data[2] = ~0;
1564
	mb1->count = 3;
1565
	mb1->param = mb->param;
1566
	fs_send(cp->reply, mb1);
1567
 
1568
	return 1;
1569
}
1570
 
1571
int
1572
serve9p1(Msgbuf* mb)
1573
{
1574
	int t, n;
1575
	Chan *cp;
1576
	Msgbuf *mb1;
1577
	Fcall fi, fo;
1578
 
1579
	assert(mb != nil);
1580
	cp = mb->chan;
1581
	assert(mb->data != nil);
1582
	if(convM2S9p1(mb->data, &fi, mb->count) == 0){
1583
		assert(cp != nil);
1584
		if(cp->protocol == nil)
1585
			return 0;
1586
		print("9p1: bad M2S conversion\n");
1587
		return error9p1(cp, mb);
1588
	}
1589
 
1590
	t = fi.type;
1591
	if(t < 0 || t >= MAXSYSCALL || (t&1) || !call9p1[t]) {
1592
		print("9p1: bad message type\n");
1593
		return error9p1(cp, mb);
1594
	}
1595
 
1596
	/*
1597
	 * allocate reply message
1598
	 */
1599
	if(t == Tread) {
1600
		mb1 = mballoc(MAXMSG+MAXDAT, cp, Mbreply2);
1601
		fo.data = (char*)(mb1->data + 8);
1602
	} else
1603
		mb1 = mballoc(MAXMSG, cp, Mbreply3);
1604
 
1605
	/*
1606
	 * call the file system
1607
	 */
1608
	assert(cp != nil);
1609
	fo.err = 0;
1610
 
1611
	(*call9p1[t])(cp, &fi, &fo);
1612
 
1613
	fo.type = t+1;
1614
	fo.tag = fi.tag;
1615
 
1616
	if(fo.err) {
1617
		if(cons.flags&errorflag)
1618
			print("\ttype %d: error: %s\n", t, errstr9p[fo.err]);
1619
		if(CHAT(cp))
1620
			print("\terror: %s\n", errstr9p[fo.err]);
1621
		fo.type = Rerror;
1622
		strncpy(fo.ename, errstr9p[fo.err], sizeof(fo.ename));
1623
	}
1624
 
1625
	n = convS2M9p1(&fo, mb1->data);
1626
	if(n == 0) {
1627
		print("9p1: bad S2M conversion\n");
1628
		mbfree(mb1);
1629
		return error9p1(cp, mb);
1630
	}
1631
	mb1->count = n;
1632
	mb1->param = mb->param;
1633
	fs_send(cp->reply, mb1);
1634
 
1635
	return 1;
1636
}