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