1 #include "all.h"
2
3 Lock wpathlock;
4
5 struct {
6 Lock flock;
7 File* ffree; /* free file structures */
8 Wpath* wfree;
9 } suballoc;
10
11 enum{
12 Finc= 128, /* allocation chunksize for files */
13 Fmax= 10000, /* maximum file structures to be allocated */
14
15 Winc= 8*128, /* allocation chunksize for wpath */
16 Wmax= 8*10000, /* maximum wpath structures to be allocated */
17 };
18
19
20 Filsys*
fsstr(char * p)21 fsstr(char *p)
22 {
23 Filsys *fs;
24
25 for(fs=filesys; fs->name; fs++)
26 if(strcmp(fs->name, p) == 0)
27 return fs;
28 return 0;
29 }
30
31 void
fileinit(Chan * cp)32 fileinit(Chan *cp)
33 {
34 File *f;
35 Tlock *t;
36
37 loop:
38 lock(&cp->flock);
39 f = cp->flist;
40 if(!f) {
41 unlock(&cp->flock);
42 return;
43 }
44 cp->flist = f->next;
45 unlock(&cp->flock);
46
47 qlock(f);
48 if(t = f->tlock) {
49 t->time = 0;
50 f->tlock = 0;
51 }
52 if(f->open & FREMOV)
53 doremove(f, 0);
54 freewp(f->wpath);
55 f->open = 0;
56 f->cp = 0;
57 qunlock(f);
58
59 goto loop;
60 }
61
62 /*
63 * returns a locked file structure
64 */
65 File*
filep(Chan * cp,int fid,int flag)66 filep(Chan *cp, int fid, int flag)
67 {
68 File *f, *prev;
69
70 if(fid == NOF)
71 return 0;
72
73 loop:
74 lock(&cp->flock);
75 for(prev=0,f=cp->flist; f; prev=f,f=f->next) {
76 if(f->fid != fid)
77 continue;
78 if(prev) {
79 prev->next = f->next;
80 f->next = cp->flist;
81 cp->flist = f;
82 }
83 goto out;
84 }
85 if(flag) {
86 f = newfp(cp);
87 if(f) {
88 f->fid = fid;
89 goto out;
90 }
91 }
92 else print("cannot find %p.%d (list=%p)\n", cp, fid, cp->flist);
93 unlock(&cp->flock);
94 return 0;
95
96 out:
97 unlock(&cp->flock);
98 qlock(f);
99 if(f->fid != fid) {
100 qunlock(f);
101 goto loop;
102 }
103 return f;
104 }
105
106 void
sublockinit(void)107 sublockinit(void)
108 {
109 lock(&suballoc.flock);
110 lock(&wpathlock);
111 conf.nfile = 0;
112 conf.nwpath = 0;
113 unlock(&suballoc.flock);
114 unlock(&wpathlock);
115 }
116
117 /*
118 * always called with cp->flock locked
119 */
120 File*
newfp(Chan * cp)121 newfp(Chan *cp)
122 {
123 File *f, *e;
124
125 retry:
126 lock(&suballoc.flock);
127 f = suballoc.ffree;
128 if(f != nil){
129 suballoc.ffree = f->list;
130 unlock(&suballoc.flock);
131 f->list = 0;
132 f->cp = cp;
133 f->next = cp->flist;
134 f->wpath = 0;
135 f->tlock = 0;
136 f->dslot = 0;
137 f->doffset = 0;
138 f->uid = 0;
139 f->cuid = 0;
140 cp->flist = f;
141 return f;
142 }
143 unlock(&suballoc.flock);
144
145 if(conf.nfile > Fmax){
146 print("%d: out of files\n", cp->chan);
147 return 0;
148 }
149
150 /*
151 * create a few new files
152 */
153 f = malloc(Finc*sizeof(*f));
154 memset(f, 0, Finc*sizeof(*f));
155 lock(&suballoc.flock);
156 for(e = f+Finc; f < e; f++){
157 qlock(f);
158 qunlock(f);
159 f->list = suballoc.ffree;
160 suballoc.ffree = f;
161 }
162 conf.nfile += Finc;
163 unlock(&suballoc.flock);
164 goto retry;
165 }
166
167 void
freefp(File * fp)168 freefp(File *fp)
169 {
170 Chan *cp;
171 File *f, *prev;
172
173 if(!fp || !(cp = fp->cp))
174 return;
175 authfree(fp);
176 lock(&cp->flock);
177 for(prev=0,f=cp->flist; f; prev=f,f=f->next) {
178 if(f != fp)
179 continue;
180 if(prev)
181 prev->next = f->next;
182 else
183 cp->flist = f->next;
184 f->cp = 0;
185 lock(&suballoc.flock);
186 f->list = suballoc.ffree;
187 suballoc.ffree = f;
188 unlock(&suballoc.flock);
189 break;
190 }
191 unlock(&cp->flock);
192 }
193
194 Wpath*
newwp(void)195 newwp(void)
196 {
197 Wpath *w, *e;
198
199 retry:
200 lock(&wpathlock);
201 w = suballoc.wfree;
202 if(w != nil){
203 suballoc.wfree = w->list;
204 unlock(&wpathlock);
205 memset(w, 0, sizeof(*w));
206 w->refs = 1;
207 w->up = 0;
208 return w;
209 }
210 unlock(&wpathlock);
211
212 if(conf.nwpath > Wmax){
213 print("out of wpaths\n");
214 return 0;
215 }
216
217 /*
218 * create a few new wpaths
219 */
220 w = malloc(Winc*sizeof(*w));
221 memset(w, 0, Winc*sizeof(*w));
222 lock(&wpathlock);
223 for(e = w+Winc; w < e; w++){
224 w->list = suballoc.wfree;
225 suballoc.wfree = w;
226 }
227 conf.nwpath += Winc;
228 unlock(&wpathlock);
229 goto retry;
230 }
231
232 /*
233 * increment the references for the whole path
234 */
235 Wpath*
getwp(Wpath * w)236 getwp(Wpath *w)
237 {
238 Wpath *nw;
239
240 lock(&wpathlock);
241 for(nw = w; nw; nw=nw->up)
242 nw->refs++;
243 unlock(&wpathlock);
244 return w;
245 }
246
247 /*
248 * decrement the reference for each element of the path
249 */
250 void
freewp(Wpath * w)251 freewp(Wpath *w)
252 {
253 lock(&wpathlock);
254 for(; w; w=w->up){
255 w->refs--;
256 if(w->refs == 0){
257 w->list = suballoc.wfree;
258 suballoc.wfree = w;
259 }
260 }
261 unlock(&wpathlock);
262 }
263
264 /*
265 * decrement the reference for just this element
266 */
267 void
putwp(Wpath * w)268 putwp(Wpath *w)
269 {
270 lock(&wpathlock);
271 w->refs--;
272 if(w->refs == 0){
273 w->list = suballoc.wfree;
274 suballoc.wfree = w;
275 }
276 unlock(&wpathlock);
277 }
278
279 int
iaccess(File * f,Dentry * d,int m)280 iaccess(File *f, Dentry *d, int m)
281 {
282 if(wstatallow)
283 return 0;
284
285 /*
286 * owner is next
287 */
288 if(f->uid == d->uid)
289 if((m<<6) & d->mode)
290 return 0;
291 /*
292 * group membership is hard
293 */
294 if(ingroup(f->uid, d->gid))
295 if((m<<3) & d->mode)
296 return 0;
297 /*
298 * other access for everyone except members of group 9999
299 */
300 if(m & d->mode){
301 /*
302 * walk directories regardless.
303 * otherwise its impossible to get
304 * from the root to noworld's directories.
305 */
306 if((d->mode & DDIR) && (m == DEXEC))
307 return 0;
308 if(!ingroup(f->uid, 9999))
309 return 0;
310 }
311 return 1;
312 }
313
314 Tlock*
tlocked(Iobuf * p,Dentry * d)315 tlocked(Iobuf *p, Dentry *d)
316 {
317 Tlock *t, *t1;
318 long qpath, tim;
319 Device dev;
320
321 tim = time(0);
322 qpath = d->qid.path;
323 dev = p->dev;
324 t1 = 0;
325 for(t=tlocks+NTLOCK-1; t>=tlocks; t--) {
326 if(t->qpath == qpath)
327 if(t->time >= tim)
328 if(devcmp(t->dev, dev) == 0)
329 return 0; /* its locked */
330 if(!t1 && t->time < tim)
331 t1 = t; /* steal first lock */
332 }
333 if(t1) {
334 t1->dev = dev;
335 t1->qpath = qpath;
336 t1->time = tim + TLOCK;
337 }
338 /* botch
339 * out of tlock nodes simulates
340 * a locked file
341 */
342 return t1;
343 }
344
345 Qid
newqid(Device dev)346 newqid(Device dev)
347 {
348 Iobuf *p;
349 Superb *sb;
350 Qid qid;
351
352 p = getbuf(dev, superaddr(dev), Bread|Bmod);
353 if(!p || checktag(p, Tsuper, QPSUPER))
354 panic("newqid: super block");
355 sb = (Superb*)p->iobuf;
356 sb->qidgen++;
357 qid.path = sb->qidgen;
358 qid.vers = 0;
359 qid.type = 0;
360 putbuf(p);
361 return qid;
362 }
363
364 /*
365 * what are legal characters in a name?
366 * only disallow control characters.
367 * a) utf avoids control characters.
368 * b) '/' may not be the separator
369 */
370 int
checkname(char * n)371 checkname(char *n)
372 {
373 int i, c;
374
375 for(i=0; i<NAMELEN; i++) {
376 c = *n & 0xff;
377 if(c == 0) {
378 if(i == 0)
379 return 1;
380 memset(n, 0, NAMELEN-i);
381 return 0;
382 }
383 if(c <= 040)
384 return 1;
385 n++;
386 }
387 return 1; /* too long */
388 }
389
390 void
bfree(Device dev,long addr,int d)391 bfree(Device dev, long addr, int d)
392 {
393 Iobuf *p;
394 long a;
395 int i;
396
397 if(!addr)
398 return;
399 if(d > 0) {
400 d--;
401 p = getbuf(dev, addr, Bread);
402 if(p) {
403 for(i=INDPERBUF-1; i>=0; i--) {
404 a = ((long*)p->iobuf)[i];
405 bfree(dev, a, d);
406 }
407 putbuf(p);
408 }
409 }
410 /*
411 * stop outstanding i/o
412 */
413 p = getbuf(dev, addr, Bprobe);
414 if(p) {
415 p->flags &= ~(Bmod|Bimm);
416 putbuf(p);
417 }
418 /*
419 * dont put written worm
420 * blocks into free list
421 */
422 if(nofree(dev, addr))
423 return;
424 p = getbuf(dev, superaddr(dev), Bread|Bmod);
425 if(!p || checktag(p, Tsuper, QPSUPER))
426 panic("bfree: super block");
427 addfree(dev, addr, (Superb*)p->iobuf);
428 putbuf(p);
429 }
430
431 long
balloc(Device dev,int tag,long qid)432 balloc(Device dev, int tag, long qid)
433 {
434 Iobuf *bp, *p;
435 Superb *sb;
436 long a;
437 int n;
438
439 p = getbuf(dev, superaddr(dev), Bread|Bmod);
440 if(!p || checktag(p, Tsuper, QPSUPER))
441 panic("balloc: super block");
442 sb = (Superb*)p->iobuf;
443
444 loop:
445 n = --sb->fbuf.nfree;
446 sb->tfree--;
447 if(n < 0 || n >= FEPERBUF)
448 panic("balloc: bad freelist");
449 a = sb->fbuf.free[n];
450 if(n <= 0) {
451 if(a == 0) {
452 sb->tfree = 0;
453 sb->fbuf.nfree = 1;
454 if(devgrow(dev, sb))
455 goto loop;
456 putbuf(p);
457 return 0;
458 }
459 bp = getbuf(dev, a, Bread);
460 if(!bp || checktag(bp, Tfree, QPNONE)) {
461 if(bp)
462 putbuf(bp);
463 putbuf(p);
464 return 0;
465 }
466 memmove(&sb->fbuf, bp->iobuf, (FEPERBUF+1)*sizeof(long));
467 putbuf(bp);
468 }
469 bp = getbuf(dev, a, Bmod);
470 memset(bp->iobuf, 0, RBUFSIZE);
471 settag(bp, tag, qid);
472 if(tag == Tind1 || tag == Tind2 || tag == Tdir)
473 bp->flags |= Bimm;
474 putbuf(bp);
475 putbuf(p);
476 return a;
477 }
478
479 void
addfree(Device dev,long addr,Superb * sb)480 addfree(Device dev, long addr, Superb *sb)
481 {
482 int n;
483 Iobuf *p;
484
485 if(addr >= sb->fsize){
486 print("addfree: bad addr %lux\n", addr);
487 return;
488 }
489 n = sb->fbuf.nfree;
490 if(n < 0 || n > FEPERBUF)
491 panic("addfree: bad freelist");
492 if(n >= FEPERBUF) {
493 p = getbuf(dev, addr, Bmod);
494 if(p == 0)
495 panic("addfree: getbuf");
496 memmove(p->iobuf, &sb->fbuf, (FEPERBUF+1)*sizeof(long));
497 settag(p, Tfree, QPNONE);
498 putbuf(p);
499 n = 0;
500 }
501 sb->fbuf.free[n++] = addr;
502 sb->fbuf.nfree = n;
503 sb->tfree++;
504 if(addr >= sb->fsize)
505 sb->fsize = addr+1;
506 }
507
508 int
Cfmt(Fmt * f1)509 Cfmt(Fmt *f1)
510 {
511 Chan *cp;
512
513 cp = va_arg(f1->args, Chan*);
514 return fmtprint(f1, "C%d.%.3d", cp->type, cp->chan);
515 }
516
517 int
Dfmt(Fmt * f1)518 Dfmt(Fmt *f1)
519 {
520 Device d;
521
522 d = va_arg(f1->args, Device);
523 return fmtprint(f1, "D%d.%d.%d.%d", d.type, d.ctrl, d.unit, d.part);
524 }
525
526 int
Afmt(Fmt * f1)527 Afmt(Fmt *f1)
528 {
529 Filta a;
530
531 a = va_arg(f1->args, Filta);
532 return fmtprint(f1, "%6lud %6lud %6lud",
533 fdf(a.f->filter[0], a.scale*60),
534 fdf(a.f->filter[1], a.scale*600),
535 fdf(a.f->filter[2], a.scale*6000));
536 }
537
538 int
Gfmt(Fmt * f1)539 Gfmt(Fmt *f1)
540 {
541 int t;
542
543 t = va_arg(f1->args, int);
544 if(t >= 0 && t < MAXTAG)
545 return fmtstrcpy(f1, tagnames[t]);
546 else
547 return fmtprint(f1, "<badtag %d>", t);
548 }
549
550 void
formatinit(void)551 formatinit(void)
552 {
553
554 fmtinstall('C', Cfmt); /* print channels */
555 fmtinstall('D', Dfmt); /* print devices */
556 fmtinstall('A', Afmt); /* print filters */
557 fmtinstall('G', Gfmt); /* print tags */
558 fmtinstall('T', Tfmt); /* print times */
559 fmtinstall('O', ofcallfmt); /* print old fcalls */
560 }
561 int
devcmp(Device d1,Device d2)562 devcmp(Device d1, Device d2)
563 {
564
565 if(d1.type == d2.type)
566 if(d1.ctrl == d2.ctrl)
567 if(d1.unit == d2.unit)
568 if(d1.part == d2.part)
569 return 0;
570 return 1;
571 }
572
573 void
rootream(Device dev,long addr)574 rootream(Device dev, long addr)
575 {
576 Iobuf *p;
577 Dentry *d;
578
579 p = getbuf(dev, addr, Bmod|Bimm);
580 memset(p->iobuf, 0, RBUFSIZE);
581 settag(p, Tdir, QPROOT);
582 d = getdir(p, 0);
583 strcpy(d->name, "/");
584 d->uid = -1;
585 d->gid = -1;
586 d->mode = DALLOC | DDIR |
587 ((DREAD|DWRITE|DEXEC) << 6) |
588 ((DREAD|DWRITE|DEXEC) << 3) |
589 ((DREAD|DWRITE|DEXEC) << 0);
590 d->qid = QID9P1(QPROOT|QPDIR,0);
591 d->atime = time(0);
592 d->mtime = d->atime;
593 putbuf(p);
594 }
595
596 int
superok(Device dev,long addr,int set)597 superok(Device dev, long addr, int set)
598 {
599 Iobuf *p;
600 Superb *s;
601 int ok;
602
603 p = getbuf(dev, addr, Bread|Bmod|Bimm);
604 s = (Superb*)p->iobuf;
605 ok = s->fsok;
606 s->fsok = set;
607 putbuf(p);
608 return ok;
609 }
610
611 void
superream(Device dev,long addr)612 superream(Device dev, long addr)
613 {
614 Iobuf *p;
615 Superb *s;
616 long i;
617
618 p = getbuf(dev, addr, Bmod|Bimm);
619 memset(p->iobuf, 0, RBUFSIZE);
620 settag(p, Tsuper, QPSUPER);
621
622 s = (Superb*)p->iobuf;
623 s->fstart = 1;
624 s->fsize = devsize(dev);
625 s->fbuf.nfree = 1;
626 s->qidgen = 10;
627 for(i=s->fsize-1; i>=addr+2; i--)
628 addfree(dev, i, s);
629 putbuf(p);
630 }
631
632 /*
633 * returns 1 if n is prime
634 * used for adjusting lengths
635 * of hashing things.
636 * there is no need to be clever
637 */
638 int
prime(long n)639 prime(long n)
640 {
641 long i;
642
643 if((n%2) == 0)
644 return 0;
645 for(i=3;; i+=2) {
646 if((n%i) == 0)
647 return 0;
648 if(i*i >= n)
649 return 1;
650 }
651 }
652
653 void
hexdump(void * a,int n)654 hexdump(void *a, int n)
655 {
656 char s1[30], s2[4];
657 uchar *p;
658 int i;
659
660 p = a;
661 s1[0] = 0;
662 for(i=0; i<n; i++) {
663 sprint(s2, " %.2ux", p[i]);
664 strcat(s1, s2);
665 if((i&7) == 7) {
666 print("%s\n", s1);
667 s1[0] = 0;
668 }
669 }
670 if(s1[0])
671 print("%s\n", s1);
672 }
673
674 long
qidpathgen(Device * dev)675 qidpathgen(Device *dev)
676 {
677 Iobuf *p;
678 Superb *sb;
679 long path;
680
681 p = getbuf(*dev, superaddr((*dev)), Bread|Bmod);
682 if(!p || checktag(p, Tsuper, QPSUPER))
683 panic("newqid: super block");
684 sb = (Superb*)p->iobuf;
685 sb->qidgen++;
686 path = sb->qidgen;
687 putbuf(p);
688 return path;
689 }
690
691