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