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