Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#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);
}