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
mkqid(Qid * qid,Dentry * d,int buggery)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
mkqidcmp(Qid * qid,Dentry * d)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
f_nop(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_flush(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_session(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_attach(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_clone(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_walk(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_clunk(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_clwalk(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_open(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_create(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_read(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_write(Chan * cp,Oldfcall * in,Oldfcall * ou)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
doremove(File * f,int iscon)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
f_remove(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_stat(Chan * cp,Oldfcall * in,Oldfcall * ou)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
f_wstat(Chan * cp,Oldfcall * in,Oldfcall * ou)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
send(Chan * c,uchar * buf,int n)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
error9p1(Chan * c,uchar * buf)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
serve9p1(Chan * chan,uchar * ib,int nib)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 }
1445