xref: /plan9/sys/src/cmd/aux/flashfs/entry.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <thread.h>
6 #include <9p.h>
7 #include "flashfs.h"
8 
9 static	int	nextfnum;
10 static	Intmap*	map;
11 static	Dir	dirproto;
12 
13 static	char	user[]	= "flash";
14 
15 	Entry	*root;
16 	ulong	used;
17 	ulong	limit;
18 	ulong	maxwrite;
19 
20 enum
21 {
22 	debug	= 0,
23 };
24 
25 static int
fnum(void)26 fnum(void)
27 {
28 	return ++nextfnum;
29 }
30 
31 static void
maxfnum(int n)32 maxfnum(int n)
33 {
34 	if(n > nextfnum)
35 		nextfnum = n;
36 }
37 
38 static int
hash(char * s)39 hash(char *s)
40 {
41 	int c, d, h;
42 
43 	h = 0;
44 	while((c = *s++) != '\0') {
45 		d = c;
46 		c ^= c << 6;
47 		h += (c << 11) ^ (c >> 1);
48 		h ^= (d << 14) + (d << 7) + (d << 4) + d;
49 	}
50 
51 	if(h < 0)
52 		return ~h;
53 	return h;
54 }
55 
56 static void
dirinit(Entry * e)57 dirinit(Entry *e)
58 {
59 	Entry **t;
60 
61 	e->size = 0;
62 	t = emalloc9p(HSIZE * sizeof(Entry*));
63 	memset(t, 0, HSIZE * sizeof(Entry*));
64 	e->htab = t;
65 	e->files = nil;
66 	e->readers = nil;
67 }
68 
69 static void
fileinit(Entry * e)70 fileinit(Entry *e)
71 {
72 	e->size = 0;
73 	e->gen[0].head = nil;
74 	e->gen[0].tail = nil;
75 	e->gen[1].head = nil;
76 	e->gen[1].tail = nil;
77 }
78 
79 static void
elfree(Extent * x)80 elfree(Extent *x)
81 {
82 	Extent *t;
83 
84 	while(x != nil) {
85 		t = x->next;
86 		used -= x->size;
87 		free(x);
88 		x = t;
89 	}
90 }
91 
92 static void
extfree(Entry * e)93 extfree(Entry *e)
94 {
95 	elfree(e->gen[0].head);
96 	elfree(e->gen[1].head);
97 }
98 
99 static void
efree(Entry * e)100 efree(Entry *e)
101 {
102 	if(debug)
103 		fprint(2, "free %s\n", e->name);
104 
105 	if(e->mode & DMDIR)
106 		free(e->htab);
107 	else
108 		extfree(e);
109 
110 	free(e->name);
111 	free(e);
112 }
113 
114 void
einit(void)115 einit(void)
116 {
117 	Entry *e;
118 
119 	e = emalloc9p(sizeof(Entry));
120 	e->ref = 1;
121 	e->parent = nil;
122 	dirinit(e);
123 	e->name = estrdup9p("");
124 	e->fnum = 0;
125 	e->mode = DMDIR | 0775;
126 	e->mnum = 0;
127 	e->mtime = 0;
128 	root = e;
129 	map = allocmap(nil);
130 }
131 
132 static void
dumptree(Entry * e,int n)133 dumptree(Entry *e, int n)
134 {
135 	Entry *l;
136 
137 	if(debug)
138 		fprint(2, "%d %s %d\n", n, e->name, e->ref);
139 
140 	if(e->mode & DMDIR) {
141 		n++;
142 		for(l = e->files; l != nil; l = l->fnext)
143 			dumptree(l, n);
144 	}
145 }
146 
147 void
edump(void)148 edump(void)
149 {
150 	if(debug)
151 		dumptree(root, 0);
152 }
153 
154 Entry *
elookup(ulong key)155 elookup(ulong key)
156 {
157 	if(key == 0)
158 		return root;
159 	maxfnum(key);
160 	return lookupkey(map, key);
161 }
162 
163 Extent *
esum(Entry * e,int sect,ulong addr,int * more)164 esum(Entry *e, int sect, ulong addr, int *more)
165 {
166 	Exts *x;
167 	Extent *t, *u;
168 
169 	x = &e->gen[eparity];
170 	t = x->tail;
171 	if(t == nil || t->sect != sect || t->addr != addr)
172 		return nil;
173 	u = t->prev;
174 	if(u != nil) {
175 		u->next = nil;
176 		*more = 1;
177 	}
178 	else {
179 		x->head = nil;
180 		*more = 0;
181 	}
182 	x->tail = u;
183 	x = &e->gen[eparity^1];
184 	u = x->head;
185 	t->next = u;
186 	x->head = t;
187 	if(u == nil)
188 		x->tail = t;
189 	else
190 		u->prev = t;
191 	return t;
192 }
193 
194 void
edestroy(Entry * e)195 edestroy(Entry *e)
196 {
197 	e->ref--;
198 	if(e->ref == 0)
199 		efree(e);
200 }
201 
202 Entry *
ecreate(Entry * d,char * name,ulong n,ulong mode,ulong mtime,char ** err)203 ecreate(Entry *d, char *name, ulong n, ulong mode, ulong mtime, char **err)
204 {
205 	int h;
206 	Entry *e, *f;
207 
208 	h = hash(name) & HMASK;
209 	for(e = d->htab[h]; e != nil; e = e->hnext) {
210 		if(strcmp(e->name, name) == 0) {
211 			*err = Eexists;
212 			return nil;
213 		}
214 	}
215 
216 	e = emalloc9p(sizeof(Entry));
217 	e->ref = 1;
218 	e->parent = d;
219 	d->ref++;
220 	f = d->htab[h];
221 	e->hnext = f;
222 	e->hprev = nil;
223 	if(f != nil)
224 		f->hprev = e;
225 	d->htab[h] = e;
226 	f = d->files;
227 	e->fnext = f;
228 	e->fprev = nil;
229 	if(f != nil)
230 		f->fprev = e;
231 	d->files = e;
232 
233 	d->ref--;
234 	e->ref++;
235 	e->name = estrdup9p(name);
236 	if(n == 0)
237 		n = fnum();
238 	else
239 		maxfnum(n);
240 	insertkey(map, n, e);
241 	e->fnum = n;
242 	e->mode = mode & d->mode;
243 	e->mnum = 0;
244 	e->mtime = mtime;
245 
246 	if(e->mode & DMDIR)
247 		dirinit(e);
248 	else
249 		fileinit(e);
250 
251 	d->mtime = mtime;
252 	return e;
253 }
254 
255 void
etrunc(Entry * e,ulong n,ulong mtime)256 etrunc(Entry *e, ulong n, ulong mtime)
257 {
258 	extfree(e);
259 	deletekey(map, e->fnum);
260 	if(n == 0)
261 		n = fnum();
262 	else
263 		maxfnum(n);
264 	e->fnum = n;
265 	e->mnum = 0;
266 	e->mtime = mtime;
267 	insertkey(map, n, e);
268 	fileinit(e);
269 	e->parent->mtime = mtime;
270 }
271 
272 char *
eremove(Entry * e)273 eremove(Entry *e)
274 {
275 	Dirr *r;
276 	Entry *d, *n, *p;
277 
278 	d = e->parent;
279 	if(d == nil)
280 		return Eperm;
281 
282 	if((e->mode & DMDIR) != 0 && e->files != nil)
283 		return Edirnotempty;
284 
285 	p = e->hprev;
286 	n = e->hnext;
287 	if(n != nil)
288 		n->hprev = p;
289 	if(p != nil)
290 		p->hnext = n;
291 	else
292 		d->htab[hash(e->name) & HMASK] = n;
293 
294 	for(r = d->readers; r != nil; r = r->next) {
295 		if(r->cur == e)
296 			r->cur = e->fnext;
297 	}
298 
299 	p = e->fprev;
300 	n = e->fnext;
301 	if(n != nil)
302 		n->fprev = p;
303 	if(p != nil)
304 		p->fnext = n;
305 	else
306 		d->files = n;
307 
308 	e->parent = nil;
309 	d->ref--;
310 	deletekey(map, e->fnum);
311 	edestroy(e);
312 	return nil;
313 }
314 
315 Entry *
ewalk(Entry * d,char * name,char ** err)316 ewalk(Entry *d, char *name, char **err)
317 {
318 	Entry *e;
319 
320 	if((d->mode & DMDIR) == 0) {
321 		*err = Enotdir;
322 		return nil;
323 	}
324 
325 	if(strcmp(name, "..") == 0) {
326 		e = d->parent;
327 		if(e == nil)
328 			return d;
329 		edestroy(d);
330 		e->ref++;
331 		return e;
332 	}
333 
334 	for(e = d->htab[hash(name) & HMASK]; e != nil; e = e->hnext) {
335 		if(strcmp(e->name, name) == 0) {
336 			d->ref--;
337 			e->ref++;
338 			return e;
339 		}
340 	}
341 
342 	*err = Enonexist;
343 	return nil;
344 }
345 
346 static void
eread0(Extent * e,Extent * x,uchar * a,ulong n,ulong off)347 eread0(Extent *e, Extent *x, uchar *a, ulong n, ulong off)
348 {
349 	uchar *a0, *a1;
350 	ulong n0, n1, o0, o1, d, z;
351 
352 	for(;;) {
353 		while(e != nil) {
354 			if(off < e->off + e->size && off + n > e->off) {
355 				if(off >= e->off) {
356 					d = off - e->off;
357 					z = e->size - d;
358 					if(n <= z) {
359 						readdata(e->sect, a, n, e->addr + d);
360 						return;
361 					}
362 					readdata(e->sect, a, z, e->addr + d);
363 					a += z;
364 					n -= z;
365 					off += z;
366 				}
367 				else {
368 					a0 = a;
369 					n0 = e->off - off;
370 					o0 = off;
371 					a += n0;
372 					n -= n0;
373 					off += n0;
374 					z = e->size;
375 					if(n <= z) {
376 						readdata(e->sect, a, n, e->addr);
377 						a = a0;
378 						n = n0;
379 						off = o0;
380 					}
381 					else {
382 						readdata(e->sect, a, z, e->addr);
383 						a1 = a + z;
384 						n1 = n - z;
385 						o1 = off + z;
386 						if(n0 < n1) {
387 							eread0(e->next, x, a0, n0, o0);
388 							a = a1;
389 							n = n1;
390 							off = o1;
391 						}
392 						else {
393 							eread0(e->next, x, a1, n1, o1);
394 							a = a0;
395 							n = n0;
396 							off = o0;
397 						}
398 					}
399 				}
400 			}
401 			e = e->next;
402 		}
403 
404 		if(x == nil)
405 			break;
406 
407 		e = x;
408 		x = nil;
409 	}
410 
411 	memset(a, 0, n);
412 }
413 
414 ulong
eread(Entry * e,int parity,void * a,ulong n,ulong off)415 eread(Entry *e, int parity, void *a, ulong n, ulong off)
416 {
417 	if(n + off >= e->size)
418 		n = e->size - off;
419 	if(n <= 0)
420 		return 0;
421 	eread0(e->gen[parity].head, e->gen[parity^1].head, a, n, off);
422 	return n;
423 }
424 
425 void
ewrite(Entry * e,Extent * x,int parity,ulong mtime)426 ewrite(Entry *e, Extent *x, int parity, ulong mtime)
427 {
428 	ulong z;
429 	Extent *t;
430 
431 	t = e->gen[parity].head;
432 	x->next = t;
433 	x->prev = nil;
434 	e->gen[parity].head = x;
435 	if(t == nil)
436 		e->gen[parity].tail = x;
437 	else
438 		t->prev = x;
439 	if(mtime != 0)
440 		e->mtime = mtime;
441 	used += x->size;
442 	z = x->off + x->size;
443 	if(z > e->size)
444 		e->size = z;
445 }
446 
447 ulong
echmod(Entry * e,ulong mode,ulong mnum)448 echmod(Entry *e, ulong mode, ulong mnum)
449 {
450 	if(mnum != 0)
451 		e->mnum = mnum;
452 	else
453 		e->mnum++;
454 	e->mode &= ~0777;
455 	e->mode |= mode;
456 	return e->mnum;
457 }
458 
459 Qid
eqid(Entry * e)460 eqid(Entry *e)
461 {
462 	Qid qid;
463 
464 	if(e->mode & DMDIR)
465 		qid.type = QTDIR;
466 	else
467 		qid.type = 0;
468 	qid.path = e->fnum;
469 	return qid;
470 }
471 
472 void
estat(Entry * e,Dir * d,int alloc)473 estat(Entry *e, Dir *d, int alloc)
474 {
475 	d->type = 'z';
476 	d->dev = 0;
477 	if(alloc) {
478 		d->uid = estrdup9p(user);
479 		d->gid = estrdup9p(user);
480 		d->muid = estrdup9p(user);
481 		d->name = estrdup9p(e->name);
482 	}
483 	else {
484 		d->uid = user;
485 		d->gid = user;
486 		d->muid = user;
487 		d->name = e->name;
488 	}
489 	d->mode = e->mode;
490 	d->length = e->size;
491 	d->atime = e->mtime;
492 	d->mtime = e->mtime;
493 	d->qid = eqid(e);
494 }
495 
496 Dirr *
ediropen(Entry * e)497 ediropen(Entry *e)
498 {
499 	Dirr *d, *t;
500 
501 	d = emalloc9p(sizeof(Dirr));
502 	d->dir = e;
503 	d->cur = e->files;
504 	t = e->readers;
505 	d->next = t;
506 	d->prev = nil;
507 	if(t != nil)
508 		t->prev = d;
509 	e->readers = d;
510 	e->ref++;
511 	return d;
512 }
513 
514 int
edirread(Dirr * r,char * a,long n)515 edirread(Dirr *r, char *a, long n)
516 {
517 	Dir d;
518 	Entry *e;
519 	int m, x;
520 
521 	m = 0;
522 	for(e = r->cur; e != nil; e = e->fnext) {
523 		estat(e, &d, 0);
524 		x = convD2M(&d, (uchar *)a, n);
525 		if(x <= BIT16SZ)
526 			break;
527 		a += x;
528 		n -= x;
529 		m += x;
530 	}
531 
532 	r->cur = e;
533 	return m;
534 }
535 
536 void
edirclose(Dirr * d)537 edirclose(Dirr *d)
538 {
539 	Entry *e;
540 	Dirr *p, *n;
541 
542 	e = d->dir;
543 	p = d->prev;
544 	n = d->next;
545 	if(n != nil)
546 		n->prev = p;
547 	if(p != nil)
548 		p->next = n;
549 	else
550 		e->readers = n;
551 
552 	edestroy(e);
553 	free(d);
554 }
555 
556 static	Renum	R;
557 
558 static void
xrenum(Extent * x)559 xrenum(Extent *x)
560 {
561 	while(x != nil) {
562 		if(x->sect == R.old)
563 			x->sect = R.new;
564 		x = x->next;
565 	}
566 }
567 
568 static void
renum(Entry * e)569 renum(Entry *e)
570 {
571 	if(e->mode & DMDIR) {
572 		for(e = e->files; e != nil; e = e->fnext)
573 			renum(e);
574 	}
575 	else {
576 		xrenum(e->gen[0].head);
577 		xrenum(e->gen[1].head);
578 	}
579 }
580 
581 void
erenum(Renum * r)582 erenum(Renum *r)
583 {
584 	R = *r;
585 	renum(root);
586 }
587