#include #include #include #include #include #include <9p.h> #include "flashfs.h" static int nextfnum; static Intmap* map; static Dir dirproto; static char user[] = "flash"; Entry *root; ulong used; ulong limit; ulong maxwrite; enum { debug = 0, }; static int fnum(void) { return ++nextfnum; } static void maxfnum(int n) { if(n > nextfnum) nextfnum = n; } static int hash(char *s) { int c, d, h; h = 0; while((c = *s++) != '\0') { d = c; c ^= c << 6; h += (c << 11) ^ (c >> 1); h ^= (d << 14) + (d << 7) + (d << 4) + d; } if(h < 0) return ~h; return h; } static void dirinit(Entry *e) { Entry **t; e->size = 0; t = emalloc9p(HSIZE * sizeof(Entry*)); memset(t, 0, HSIZE * sizeof(Entry*)); e->htab = t; e->files = nil; e->readers = nil; } static void fileinit(Entry *e) { e->size = 0; e->gen[0].head = nil; e->gen[0].tail = nil; e->gen[1].head = nil; e->gen[1].tail = nil; } static void elfree(Extent *x) { Extent *t; while(x != nil) { t = x->next; used -= x->size; free(x); x = t; } } static void extfree(Entry *e) { elfree(e->gen[0].head); elfree(e->gen[1].head); } static void efree(Entry *e) { if(debug) fprint(2, "free %s\n", e->name); if(e->mode & DMDIR) free(e->htab); else extfree(e); free(e->name); free(e); } void einit(void) { Entry *e; e = emalloc9p(sizeof(Entry)); e->ref = 1; e->parent = nil; dirinit(e); e->name = estrdup9p(""); e->fnum = 0; e->mode = DMDIR | 0775; e->mnum = 0; e->mtime = 0; root = e; map = allocmap(nil); } static void dumptree(Entry *e, int n) { Entry *l; if(debug) fprint(2, "%d %s %d\n", n, e->name, e->ref); if(e->mode & DMDIR) { n++; for(l = e->files; l != nil; l = l->fnext) dumptree(l, n); } } void edump(void) { if(debug) dumptree(root, 0); } Entry * elookup(ulong key) { if(key == 0) return root; maxfnum(key); return lookupkey(map, key); } Extent * esum(Entry *e, int sect, ulong addr, int *more) { Exts *x; Extent *t, *u; x = &e->gen[eparity]; t = x->tail; if(t == nil || t->sect != sect || t->addr != addr) return nil; u = t->prev; if(u != nil) { u->next = nil; *more = 1; } else { x->head = nil; *more = 0; } x->tail = u; x = &e->gen[eparity^1]; u = x->head; t->next = u; x->head = t; if(u == nil) x->tail = t; else u->prev = t; return t; } void edestroy(Entry *e) { e->ref--; if(e->ref == 0) efree(e); } Entry * ecreate(Entry *d, char *name, ulong n, ulong mode, ulong mtime, char **err) { int h; Entry *e, *f; h = hash(name) & HMASK; for(e = d->htab[h]; e != nil; e = e->hnext) { if(strcmp(e->name, name) == 0) { *err = Eexists; return nil; } } e = emalloc9p(sizeof(Entry)); e->ref = 1; e->parent = d; d->ref++; f = d->htab[h]; e->hnext = f; e->hprev = nil; if(f != nil) f->hprev = e; d->htab[h] = e; f = d->files; e->fnext = f; e->fprev = nil; if(f != nil) f->fprev = e; d->files = e; d->ref--; e->ref++; e->name = estrdup9p(name); if(n == 0) n = fnum(); else maxfnum(n); insertkey(map, n, e); e->fnum = n; e->mode = mode & d->mode; e->mnum = 0; e->mtime = mtime; if(e->mode & DMDIR) dirinit(e); else fileinit(e); d->mtime = mtime; return e; } void etrunc(Entry *e, ulong n, ulong mtime) { extfree(e); deletekey(map, e->fnum); if(n == 0) n = fnum(); else maxfnum(n); e->fnum = n; e->mnum = 0; e->mtime = mtime; insertkey(map, n, e); fileinit(e); e->parent->mtime = mtime; } char * eremove(Entry *e) { Dirr *r; Entry *d, *n, *p; d = e->parent; if(d == nil) return Eperm; if((e->mode & DMDIR) != 0 && e->files != nil) return Edirnotempty; p = e->hprev; n = e->hnext; if(n != nil) n->hprev = p; if(p != nil) p->hnext = n; else d->htab[hash(e->name) & HMASK] = n; for(r = d->readers; r != nil; r = r->next) { if(r->cur == e) r->cur = e->fnext; } p = e->fprev; n = e->fnext; if(n != nil) n->fprev = p; if(p != nil) p->fnext = n; else d->files = n; e->parent = nil; d->ref--; deletekey(map, e->fnum); edestroy(e); return nil; } Entry * ewalk(Entry *d, char *name, char **err) { Entry *e; if((d->mode & DMDIR) == 0) { *err = Enotdir; return nil; } if(strcmp(name, "..") == 0) { e = d->parent; if(e == nil) return d; edestroy(d); e->ref++; return e; } for(e = d->htab[hash(name) & HMASK]; e != nil; e = e->hnext) { if(strcmp(e->name, name) == 0) { d->ref--; e->ref++; return e; } } *err = Enonexist; return nil; } static void eread0(Extent *e, Extent *x, uchar *a, ulong n, ulong off) { uchar *a0, *a1; ulong n0, n1, o0, o1, d, z; for(;;) { while(e != nil) { if(off < e->off + e->size && off + n > e->off) { if(off >= e->off) { d = off - e->off; z = e->size - d; if(n <= z) { readdata(e->sect, a, n, e->addr + d); return; } readdata(e->sect, a, z, e->addr + d); a += z; n -= z; off += z; } else { a0 = a; n0 = e->off - off; o0 = off; a += n0; n -= n0; off += n0; z = e->size; if(n <= z) { readdata(e->sect, a, n, e->addr); a = a0; n = n0; off = o0; } else { readdata(e->sect, a, z, e->addr); a1 = a + z; n1 = n - z; o1 = off + z; if(n0 < n1) { eread0(e->next, x, a0, n0, o0); a = a1; n = n1; off = o1; } else { eread0(e->next, x, a1, n1, o1); a = a0; n = n0; off = o0; } } } } e = e->next; } if(x == nil) break; e = x; x = nil; } memset(a, 0, n); } ulong eread(Entry *e, int parity, void *a, ulong n, ulong off) { if(n + off >= e->size) n = e->size - off; if(n <= 0) return 0; eread0(e->gen[parity].head, e->gen[parity^1].head, a, n, off); return n; } void ewrite(Entry *e, Extent *x, int parity, ulong mtime) { ulong z; Extent *t; t = e->gen[parity].head; x->next = t; x->prev = nil; e->gen[parity].head = x; if(t == nil) e->gen[parity].tail = x; else t->prev = x; if(mtime != 0) e->mtime = mtime; used += x->size; z = x->off + x->size; if(z > e->size) e->size = z; } ulong echmod(Entry *e, ulong mode, ulong mnum) { if(mnum != 0) e->mnum = mnum; else e->mnum++; e->mode &= ~0777; e->mode |= mode; return e->mnum; } Qid eqid(Entry *e) { Qid qid; if(e->mode & DMDIR) qid.type = QTDIR; else qid.type = 0; qid.path = e->fnum; return qid; } void estat(Entry *e, Dir *d, int alloc) { d->type = 'z'; d->dev = 0; if(alloc) { d->uid = estrdup9p(user); d->gid = estrdup9p(user); d->muid = estrdup9p(user); d->name = estrdup9p(e->name); } else { d->uid = user; d->gid = user; d->muid = user; d->name = e->name; } d->mode = e->mode; d->length = e->size; d->atime = e->mtime; d->mtime = e->mtime; d->qid = eqid(e); } Dirr * ediropen(Entry *e) { Dirr *d, *t; d = emalloc9p(sizeof(Dirr)); d->dir = e; d->cur = e->files; t = e->readers; d->next = t; d->prev = nil; if(t != nil) t->prev = d; e->readers = d; e->ref++; return d; } int edirread(Dirr *r, char *a, long n) { Dir d; Entry *e; int m, x; m = 0; for(e = r->cur; e != nil; e = e->fnext) { estat(e, &d, 0); x = convD2M(&d, (uchar *)a, n); if(x <= BIT16SZ) break; a += x; n -= x; m += x; } r->cur = e; return m; } void edirclose(Dirr *d) { Entry *e; Dirr *p, *n; e = d->dir; p = d->prev; n = d->next; if(n != nil) n->prev = p; if(p != nil) p->next = n; else e->readers = n; edestroy(e); free(d); } static Renum R; static void xrenum(Extent *x) { while(x != nil) { if(x->sect == R.old) x->sect = R.new; x = x->next; } } static void renum(Entry *e) { if(e->mode & DMDIR) { for(e = e->files; e != nil; e = e->fnext) renum(e); } else { xrenum(e->gen[0].head); xrenum(e->gen[1].head); } } void erenum(Renum *r) { R = *r; renum(root); }