diff options
author | rsc <devnull@localhost> | 2003-11-23 17:55:34 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2003-11-23 17:55:34 +0000 |
commit | 7763a61a3582ef330bca54f225e8ec5325fbd35e (patch) | |
tree | 952957eef4d70ecbd30c58e3a0dacd6b3a753a54 /src/cmd/vac/file.c | |
parent | 7a4ee46d253e291044bba2d0c54b818b67ac013c (diff) | |
download | plan9port-7763a61a3582ef330bca54f225e8ec5325fbd35e.tar.gz plan9port-7763a61a3582ef330bca54f225e8ec5325fbd35e.tar.bz2 plan9port-7763a61a3582ef330bca54f225e8ec5325fbd35e.zip |
start thinking about vac -- doesn't build yet
Diffstat (limited to 'src/cmd/vac/file.c')
-rw-r--r-- | src/cmd/vac/file.c | 1214 |
1 files changed, 1214 insertions, 0 deletions
diff --git a/src/cmd/vac/file.c b/src/cmd/vac/file.c new file mode 100644 index 00000000..900422d2 --- /dev/null +++ b/src/cmd/vac/file.c @@ -0,0 +1,1214 @@ +#include "stdinc.h" +#include "vac.h" +#include "dat.h" +#include "fns.h" +#include "error.h" + +/* + * locking order is upwards. A thread can hold the lock for a VacFile + * and then acquire the lock of its parent + */ + +struct VacFile { + /* meta data for file: protected by the lk in the parent */ + int ref; /* holds this data structure up */ + VacFS *fs; /* immutable */ + + int removed; /* file has been removed */ + int dirty; /* dir is dirty with respect to meta data in block */ + ulong block; /* block offset withing msource for this file's meta data */ + + VacDir dir; /* meta data for this file */ + + VacFile *up; /* parent file */ + VacFile *next; /* sibling */ + + /* data for file */ + VtLock *lk; /* lock for source and msource */ + Source *source; + Source *msource; /* for directories: meta data for children */ + VacFile *down; /* children */ +}; + +static int vfMetaFlush(VacFile*); +static ulong msAlloc(Source *ms, ulong, int n); + +static void +vfRUnlock(VacFile *vf) +{ + vtRUnlock(vf->lk); +} + + +static int +vfRLock(VacFile *vf) +{ + vtRLock(vf->lk); + if(vf->source == nil) { + vfRUnlock(vf); + vtSetError(ERemoved); + return 0; + } + return 1; +} + +static void +vfUnlock(VacFile *vf) +{ + vtUnlock(vf->lk); +} + +static int +vfLock(VacFile *vf) +{ + vtLock(vf->lk); + if(vf->source == nil) { + vfUnlock(vf); + vtSetError(ERemoved); + return 0; + } + return 1; +} + +static void +vfMetaLock(VacFile *vf) +{ + assert(vf->up->msource != nil); + vtLock(vf->up->lk); +} + +static void +vfMetaUnlock(VacFile *vf) +{ + vtUnlock(vf->up->lk); +} + + +static void +vfRAccess(VacFile* vf) +{ + vfMetaLock(vf); + vf->dir.atime = time(0L); + vf->dirty = 1; + vfMetaUnlock(vf); + vfMetaFlush(vf); +} + +static void +vfWAccess(VacFile* vf, char *mid) +{ + vfMetaLock(vf); + vf->dir.atime = vf->dir.mtime = time(0L); + if(strcmp(vf->dir.mid, mid) != 0) { + vtMemFree(vf->dir.mid); + vf->dir.mid = vtStrDup(mid); + } + vf->dir.mcount++; + vf->dirty = 1; + vfMetaUnlock(vf); + vfMetaFlush(vf); +} + +void +vdCleanup(VacDir *dir) +{ + vtMemFree(dir->elem); + dir->elem = nil; + vtMemFree(dir->uid); + dir->uid = nil; + vtMemFree(dir->gid); + dir->gid = nil; + vtMemFree(dir->mid); + dir->mid = nil; +} + +void +vdCopy(VacDir *dst, VacDir *src) +{ + *dst = *src; + dst->elem = vtStrDup(src->elem); + dst->uid = vtStrDup(src->uid); + dst->gid = vtStrDup(src->gid); + dst->mid = vtStrDup(src->mid); +} + +static int +mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me) +{ + int i; + int b, t, x; + + /* binary search within block */ + b = 0; + t = mb->nindex; + while(b < t) { + i = (b+t)>>1; + if(!meUnpack(me, mb, i)) + return 0; + if(mb->unbotch) + x = meCmpNew(me, elem); + else + x = meCmp(me, elem); + + if(x == 0) { + *ri = i; + return 1; + } + + if(x < 0) + b = i+1; + else /* x > 0 */ + t = i; + } + + assert(b == t); + + *ri = b; /* b is the index to insert this entry */ + memset(me, 0, sizeof(*me)); + + return 1; +} + +static void +mbInit(MetaBlock *mb, uchar *p, int n) +{ + memset(mb, 0, sizeof(MetaBlock)); + mb->maxsize = n; + mb->buf = p; + mb->maxindex = n/100; + mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize; +} + +static int +vfMetaFlush(VacFile *vf) +{ + VacFile *vfp; + Lump *u; + MetaBlock mb; + MetaEntry me, nme; + uchar *p; + int i, n, moved; + +//print("vfMetaFlush %s\n", vf->dir.elem); + + /* assume name has not changed for the moment */ + + vfMetaLock(vf); + + vfp = vf->up; + moved = 0; + + u = sourceGetLump(vfp->msource, vf->block, 0, 1); + if(u == nil) + goto Err; + + if(!mbUnpack(&mb, u->data, u->asize)) + goto Err; + if(!mbSearch(&mb, vf->dir.elem, &i, &me) || me.p == nil) + goto Err; + + nme = me; + n = vdSize(&vf->dir); +//print("old size %d new size %d\n", me.size, n); + if(n <= nme.size) { + nme.size = n; + } else { + /* try expand entry? */ + p = mbAlloc(&mb, n); +//print("alloced %ld\n", p - mb.buf); + if(p == nil) { +assert(0); + /* much more work */ + } + nme.p = p; + nme.size = n; + } + + mbDelete(&mb, i, &me); + memset(me.p, 0, me.size); + if(!moved) { + vdPack(&vf->dir, &nme); + mbInsert(&mb, i, &nme); + } + + mbPack(&mb); + lumpDecRef(u, 1); + + vf->dirty = 0; + + vfMetaUnlock(vf); + return 1; + +Err: + lumpDecRef(u, 1); + vfMetaUnlock(vf); + return 0; +} + +static VacFile * +vfAlloc(VacFS *fs) +{ + VacFile *vf; + + vf = vtMemAllocZ(sizeof(VacFile)); + vf->lk = vtLockAlloc(); + vf->ref = 1; + vf->fs = fs; + return vf; +} + +static void +vfFree(VacFile *vf) +{ + sourceFree(vf->source); + vtLockFree(vf->lk); + sourceFree(vf->msource); + vdCleanup(&vf->dir); + + vtMemFree(vf); +} + +/* the file is locked already */ +static VacFile * +dirLookup(VacFile *vf, char *elem) +{ + int i, j, nb; + MetaBlock mb; + MetaEntry me; + Lump *u; + Source *meta; + VacFile *nvf; + + meta = vf->msource; + u = nil; + nb = sourceGetNumBlocks(meta); + for(i=0; i<nb; i++) { + u = sourceGetLump(meta, i, 1, 1); + if(u == nil) + goto Err; + if(!mbUnpack(&mb, u->data, u->asize)) + goto Err; + if(!mbSearch(&mb, elem, &j, &me)) + goto Err; + if(me.p != nil) { + nvf = vfAlloc(vf->fs); + if(!vdUnpack(&nvf->dir, &me)) { + vfFree(nvf); + goto Err; + } + lumpDecRef(u, 1); + nvf->block = i; + return nvf; + } + + lumpDecRef(u, 1); + u = nil; + } + vtSetError("file does not exist"); + /* fall through */ +Err: + lumpDecRef(u, 1); + return nil; +} + +VacFile * +vfRoot(VacFS *fs, uchar *score) +{ + VtEntry e; + Lump *u, *v; + Source *r, *r0, *r1, *r2; + MetaBlock mb; + MetaEntry me; + VacFile *root, *mr; + + root = nil; + mr = nil; + r0 = nil; + r1 = nil; + r2 = nil; + v = nil; + r = nil; + + u = cacheGetLump(fs->cache, score, VtDirType, fs->bsize); + if(u == nil) + goto Err; + if(!fs->readOnly) { + v = cacheAllocLump(fs->cache, VtDirType, fs->bsize, 1); + if(v == nil) { + vtUnlock(u->lk); + goto Err; + } + v->gen = u->gen; + v->asize = u->asize; + v->state = LumpActive; + memmove(v->data, u->data, v->asize); + lumpDecRef(u, 1); + u = v; + v = nil; + } + vtUnlock(u->lk); + vtEntryUnpack(&e, u->data, 2); + if(e.flags == 0){ /* just one entry */ + r = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly); + if(r == nil) + goto Err; + r0 = sourceOpen(r, 0, fs->readOnly); + if(r0 == nil) + goto Err; + r1 = sourceOpen(r, 1, fs->readOnly); + if(r1 == nil) + goto Err; + r2 = sourceOpen(r, 2, fs->readOnly); + if(r2 == nil) + goto Err; + sourceFree(r); + r = nil; + }else{ + r0 = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly); + if(r0 == nil) + goto Err; + r1 = sourceAlloc(fs->cache, u, 0, 1, fs->readOnly); + if(r1 == nil) + goto Err; + r2 = sourceAlloc(fs->cache, u, 0, 2, fs->readOnly); + if(r2 == nil) + goto Err; + } + lumpDecRef(u, 0); + u = sourceGetLump(r2, 0, 1, 0); + if(u == nil) + goto Err; + + mr = vfAlloc(fs); + mr->msource = r2; + r2 = nil; + + root = vfAlloc(fs); + root->up = mr; + root->source = r0; + r0 = nil; + root->msource = r1; + r1 = nil; + + mr->down = root; + + if(!mbUnpack(&mb, u->data, u->asize)) + goto Err; + + if(!meUnpack(&me, &mb, 0)) + goto Err; + if(!vdUnpack(&root->dir, &me)) + goto Err; + + vfRAccess(root); + lumpDecRef(u, 0); + sourceFree(r2); + + return root; +Err: + lumpDecRef(u, 0); + lumpDecRef(v, 0); + if(r0) + sourceFree(r0); + if(r1) + sourceFree(r1); + if(r2) + sourceFree(r2); + if(r) + sourceFree(r); + if(mr) + vfFree(mr); + if(root) + vfFree(root); + + return nil; +} + +VacFile * +vfWalk(VacFile *vf, char *elem) +{ + VacFile *nvf; + + vfRAccess(vf); + + if(elem[0] == 0) { + vtSetError("illegal path element"); + return nil; + } + if(!vfIsDir(vf)) { + vtSetError("not a directory"); + return nil; + } + + if(strcmp(elem, ".") == 0) { + return vfIncRef(vf); + } + + if(strcmp(elem, "..") == 0) { + if(vfIsRoot(vf)) + return vfIncRef(vf); + return vfIncRef(vf->up); + } + + if(!vfLock(vf)) + return nil; + + for(nvf = vf->down; nvf; nvf=nvf->next) { + if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) { + nvf->ref++; + goto Exit; + } + } + + nvf = dirLookup(vf, elem); + if(nvf == nil) + goto Err; + nvf->source = sourceOpen(vf->source, nvf->dir.entry, vf->fs->readOnly); + if(nvf->source == nil) + goto Err; + if(nvf->dir.mode & ModeDir) { + nvf->msource = sourceOpen(vf->source, nvf->dir.mentry, vf->fs->readOnly); + if(nvf->msource == nil) + goto Err; + } + + /* link in and up parent ref count */ + nvf->next = vf->down; + vf->down = nvf; + nvf->up = vf; + vfIncRef(vf); +Exit: + vfUnlock(vf); + return nvf; +Err: + vfUnlock(vf); + if(nvf != nil) + vfFree(nvf); + return nil; +} + +VacFile * +vfOpen(VacFS *fs, char *path) +{ + VacFile *vf, *nvf; + char *p, elem[VtMaxStringSize]; + int n; + + vf = fs->root; + vfIncRef(vf); + while(*path != 0) { + for(p = path; *p && *p != '/'; p++) + ; + n = p - path; + if(n > 0) { + if(n > VtMaxStringSize) { + vtSetError("path element too long"); + goto Err; + } + memmove(elem, path, n); + elem[n] = 0; + nvf = vfWalk(vf, elem); + if(nvf == nil) + goto Err; + vfDecRef(vf); + vf = nvf; + } + if(*p == '/') + p++; + path = p; + } + return vf; +Err: + vfDecRef(vf); + return nil; +} + +VacFile * +vfCreate(VacFile *vf, char *elem, ulong mode, char *user) +{ + VacFile *nvf; + VacDir *dir; + int n, i; + uchar *p; + Source *pr, *r, *mr; + int isdir; + MetaBlock mb; + MetaEntry me; + Lump *u; + + if(!vfLock(vf)) + return nil; + + r = nil; + mr = nil; + u = nil; + + for(nvf = vf->down; nvf; nvf=nvf->next) { + if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) { + nvf = nil; + vtSetError(EExists); + goto Err; + } + } + + nvf = dirLookup(vf, elem); + if(nvf != nil) { + vtSetError(EExists); + goto Err; + } + + nvf = vfAlloc(vf->fs); + isdir = mode & ModeDir; + + pr = vf->source; + r = sourceCreate(pr, pr->psize, pr->dsize, isdir, 0); + if(r == nil) + goto Err; + if(isdir) { + mr = sourceCreate(pr, pr->psize, pr->dsize, 0, r->block*pr->epb + r->entry); + if(mr == nil) + goto Err; + } + + dir = &nvf->dir; + dir->elem = vtStrDup(elem); + dir->entry = r->block*pr->epb + r->entry; + dir->gen = r->gen; + if(isdir) { + dir->mentry = mr->block*pr->epb + mr->entry; + dir->mgen = mr->gen; + } + dir->size = 0; + dir->qid = vf->fs->qid++; + dir->uid = vtStrDup(user); + dir->gid = vtStrDup(vf->dir.gid); + dir->mid = vtStrDup(user); + dir->mtime = time(0L); + dir->mcount = 0; + dir->ctime = dir->mtime; + dir->atime = dir->mtime; + dir->mode = mode; + + n = vdSize(dir); + nvf->block = msAlloc(vf->msource, 0, n); + if(nvf->block == NilBlock) + goto Err; + u = sourceGetLump(vf->msource, nvf->block, 0, 1); + if(u == nil) + goto Err; + if(!mbUnpack(&mb, u->data, u->asize)) + goto Err; + p = mbAlloc(&mb, n); + if(p == nil) + goto Err; + + if(!mbSearch(&mb, elem, &i, &me)) + goto Err; + assert(me.p == nil); + me.p = p; + me.size = n; + + vdPack(dir, &me); + mbInsert(&mb, i, &me); + mbPack(&mb); + lumpDecRef(u, 1); + + nvf->source = r; + nvf->msource = mr; + + /* link in and up parent ref count */ + nvf->next = vf->down; + vf->down = nvf; + nvf->up = vf; + vfIncRef(vf); + + vfWAccess(vf, user); + + vfUnlock(vf); + return nvf; + +Err: + lumpDecRef(u, 1); + if(r) + sourceRemove(r); + if(mr) + sourceRemove(mr); + if(nvf) + vfFree(nvf); + vfUnlock(vf); + return 0; +} + + +int +vfRead(VacFile *vf, void *buf, int cnt, vlong offset) +{ + Source *s; + uvlong size; + ulong bn; + int off, dsize, n, nn; + Lump *u; + uchar *b; + +if(0)fprint(2, "vfRead: %s %d, %lld\n", vf->dir.elem, cnt, offset); + + if(!vfRLock(vf)) + return -1; + + s = vf->source; + + dsize = s->dsize; + size = sourceGetSize(s); + + if(offset < 0) { + vtSetError(EBadOffset); + goto Err; + } + + vfRAccess(vf); + + if(offset >= size) + offset = size; + + if(cnt > size-offset) + cnt = size-offset; + bn = offset/dsize; + off = offset%dsize; + b = buf; + while(cnt > 0) { + u = sourceGetLump(s, bn, 1, 0); + if(u == nil) + goto Err; + if(u->asize <= off) { + lumpDecRef(u, 0); + goto Err; + } + n = cnt; + if(n > dsize-off) + n = dsize-off; + nn = u->asize-off; + if(nn > n) + nn = n; + memmove(b, u->data+off, nn); + memset(b+nn, 0, n-nn); + off = 0; + bn++; + cnt -= n; + b += n; + lumpDecRef(u, 0); + } + vfRUnlock(vf); + return b-(uchar*)buf; +Err: + vfRUnlock(vf); + return -1; +} + +int +vfWrite(VacFile *vf, void *buf, int cnt, vlong offset, char *user) +{ + Source *s; + ulong bn; + int off, dsize, n; + Lump *u; + uchar *b; + + USED(user); + + if(!vfLock(vf)) + return -1; + + if(vf->fs->readOnly) { + vtSetError(EReadOnly); + goto Err; + } + + if(vf->dir.mode & ModeDir) { + vtSetError(ENotFile); + goto Err; + } +if(0)fprint(2, "vfWrite: %s %d, %lld\n", vf->dir.elem, cnt, offset); + + s = vf->source; + dsize = s->dsize; + + if(offset < 0) { + vtSetError(EBadOffset); + goto Err; + } + + vfWAccess(vf, user); + + bn = offset/dsize; + off = offset%dsize; + b = buf; + while(cnt > 0) { + n = cnt; + if(n > dsize-off) + n = dsize-off; + if(!sourceSetDepth(s, offset+n)) + goto Err; + u = sourceGetLump(s, bn, 0, 0); + if(u == nil) + goto Err; + if(u->asize < dsize) { + vtSetError("runt block"); + lumpDecRef(u, 0); + goto Err; + } + memmove(u->data+off, b, n); + off = 0; + cnt -= n; + b += n; + offset += n; + bn++; + lumpDecRef(u, 0); + if(!sourceSetSize(s, offset)) + goto Err; + } + vfLock(vf); + return b-(uchar*)buf; +Err: + vfLock(vf); + return -1; +} + +int +vfGetDir(VacFile *vf, VacDir *dir) +{ + if(!vfRLock(vf)) + return 0; + + vfMetaLock(vf); + vdCopy(dir, &vf->dir); + vfMetaUnlock(vf); + + if(!vfIsDir(vf)) + dir->size = sourceGetSize(vf->source); + vfRUnlock(vf); + + return 1; +} + +uvlong +vfGetId(VacFile *vf) +{ + /* immutable */ + return vf->dir.qid; +} + +ulong +vfGetMcount(VacFile *vf) +{ + ulong mcount; + + vfMetaLock(vf); + mcount = vf->dir.mcount; + vfMetaUnlock(vf); + return mcount; +} + + +int +vfIsDir(VacFile *vf) +{ + /* immutable */ + return (vf->dir.mode & ModeDir) != 0; +} + +int +vfIsRoot(VacFile *vf) +{ + return vf == vf->fs->root; +} + +int +vfGetSize(VacFile *vf, uvlong *size) +{ + if(!vfRLock(vf)) + return 0; + *size = sourceGetSize(vf->source); + vfRUnlock(vf); + + return 1; +} + +static int +vfMetaRemove(VacFile *vf, char *user) +{ + Lump *u; + MetaBlock mb; + MetaEntry me; + int i; + VacFile *vfp; + + vfp = vf->up; + + vfWAccess(vfp, user); + + vfMetaLock(vf); + + u = sourceGetLump(vfp->msource, vf->block, 0, 1); + if(u == nil) + goto Err; + + if(!mbUnpack(&mb, u->data, u->asize)) + goto Err; + if(!mbSearch(&mb, vf->dir.elem, &i, &me) || me.p == nil) + goto Err; +print("deleting %d entry\n", i); + mbDelete(&mb, i, &me); + memset(me.p, 0, me.size); + mbPack(&mb); + + lumpDecRef(u, 1); + + vf->removed = 1; + vf->block = NilBlock; + + vfMetaUnlock(vf); + return 1; + +Err: + lumpDecRef(u, 1); + vfMetaUnlock(vf); + return 0; +} + + +static int +vfCheckEmpty(VacFile *vf) +{ + int i, n; + Lump *u; + MetaBlock mb; + Source *r; + + r = vf->msource; + n = sourceGetNumBlocks(r); + for(i=0; i<n; i++) { + u = sourceGetLump(r, i, 1, 1); + if(u == nil) + goto Err; + if(!mbUnpack(&mb, u->data, u->asize)) + goto Err; + if(mb.nindex > 0) { + vtSetError(ENotEmpty); + goto Err; + } + lumpDecRef(u, 1); + } + return 1; +Err: + lumpDecRef(u, 1); + return 0; +} + +int +vfRemove(VacFile *vf, char *user) +{ + /* can not remove the root */ + if(vfIsRoot(vf)) { + vtSetError(ERoot); + return 0; + } + + if(!vfLock(vf)) + return 0; + + if(vfIsDir(vf) && !vfCheckEmpty(vf)) + goto Err; + + assert(vf->down == nil); + + sourceRemove(vf->source); + vf->source = nil; + if(vf->msource) { + sourceRemove(vf->msource); + vf->msource = nil; + } + + vfUnlock(vf); + + if(!vfMetaRemove(vf, user)) + return 0; + + return 1; + +Err: + vfUnlock(vf); + return 0; +} + +VacFile * +vfIncRef(VacFile *vf) +{ + vfMetaLock(vf); + assert(vf->ref > 0); + vf->ref++; + vfMetaUnlock(vf); + return vf; +} + +void +vfDecRef(VacFile *vf) +{ + VacFile *p, *q, **qq; + + if(vf->up == nil) { + vfFree(vf); + return; + } + + vfMetaLock(vf); + vf->ref--; + if(vf->ref > 0) { + vfMetaUnlock(vf); + return; + } + assert(vf->ref == 0); + assert(vf->down == nil); + + p = vf->up; + qq = &p->down; + for(q = *qq; q; qq=&q->next,q=*qq) + if(q == vf) + break; + assert(q != nil); + *qq = vf->next; + + vfMetaUnlock(vf); + vfFree(vf); + + vfDecRef(p); +} + +int +vfGetVtEntry(VacFile *vf, VtEntry *e) +{ + int res; + + if(!vfRLock(vf)) + return 0; + res = sourceGetVtEntry(vf->source, e); + vfRUnlock(vf); + return res; +} + +int +vfGetBlockScore(VacFile *vf, ulong bn, uchar score[VtScoreSize]) +{ + Lump *u; + int ret, off; + Source *r; + + if(!vfRLock(vf)) + return 0; + + r = vf->source; + + u = sourceWalk(r, bn, 1, &off); + if(u == nil){ + vfRUnlock(vf); + return 0; + } + + ret = lumpGetScore(u, off, score); + lumpDecRef(u, 0); + vfRUnlock(vf); + + return ret; +} + +VacFile * +vfGetParent(VacFile *vf) +{ + if(vfIsRoot(vf)) + return vfIncRef(vf); + return vfIncRef(vf->up); +} + +static VacDirEnum * +vdeAlloc(VacFile *vf) +{ + VacDirEnum *ds; + + if(!(vf->dir.mode & ModeDir)) { + vtSetError(ENotDir); + vfDecRef(vf); + return nil; + } + + ds = vtMemAllocZ(sizeof(VacDirEnum)); + ds->file = vf; + + return ds; +} + +VacDirEnum * +vdeOpen(VacFS *fs, char *path) +{ + VacFile *vf; + + vf = vfOpen(fs, path); + if(vf == nil) + return nil; + + return vdeAlloc(vf); +} + +VacDirEnum * +vfDirEnum(VacFile *vf) +{ + return vdeAlloc(vfIncRef(vf)); +} + +static int +dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size) +{ + Lump *u; + ulong bn; + VtEntry e; + + bn = elem/s->epb; + elem -= bn*s->epb; + + u = sourceGetLump(s, bn, 1, 1); + if(u == nil) + goto Err; + if(u->asize < (elem+1)*VtEntrySize) { + vtSetError(ENoDir); + goto Err; + } + vtEntryUnpack(&e, u->data, elem); + if(!(e.flags & VtEntryActive) || e.gen != gen) { +fprint(2, "gen mismatch\n"); + vtSetError(ENoDir); + goto Err; + } + + *size = e.size; + lumpDecRef(u, 1); + return 1; + +Err: + lumpDecRef(u, 1); + return 0; +} + +int +vdeRead(VacDirEnum *ds, VacDir *dir, int n) +{ + ulong nb; + int i; + Source *meta, *source; + MetaBlock mb; + MetaEntry me; + Lump *u; + + vfRAccess(ds->file); + + if(!vfRLock(ds->file)) + return -1; + + i = 0; + u = nil; + source = ds->file->source; + meta = ds->file->msource; + nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize; + + if(ds->block >= nb) + goto Exit; + u = sourceGetLump(meta, ds->block, 1, 1); + if(u == nil) + goto Err; + if(!mbUnpack(&mb, u->data, u->asize)) + goto Err; + + for(i=0; i<n; i++) { + while(ds->index >= mb.nindex) { + lumpDecRef(u, 1); + u = nil; + ds->index = 0; + ds->block++; + if(ds->block >= nb) + goto Exit; + u = sourceGetLump(meta, ds->block, 1, 1); + if(u == nil) + goto Err; + if(!mbUnpack(&mb, u->data, u->asize)) + goto Err; + } + if(!meUnpack(&me, &mb, ds->index)) + goto Err; + if(dir != nil) { + if(!vdUnpack(&dir[i], &me)) + goto Err; + if(!(dir[i].mode & ModeDir)) + if(!dirEntrySize(source, dir[i].entry, dir[i].gen, &dir[i].size)) + goto Err; + } + ds->index++; + } +Exit: + lumpDecRef(u, 1); + vfRUnlock(ds->file); + return i; +Err: + lumpDecRef(u, 1); + vfRUnlock(ds->file); + n = i; + for(i=0; i<n ; i++) + vdCleanup(&dir[i]); + return -1; +} + +void +vdeFree(VacDirEnum *ds) +{ + if(ds == nil) + return; + vfDecRef(ds->file); + vtMemFree(ds); +} + +static ulong +msAlloc(Source *ms, ulong start, int n) +{ + ulong nb, i; + Lump *u; + MetaBlock mb; + + nb = sourceGetNumBlocks(ms); + u = nil; + if(start > nb) + start = nb; + for(i=start; i<nb; i++) { + u = sourceGetLump(ms, i, 1, 1); + if(u == nil) + goto Err; + if(!mbUnpack(&mb, u->data, ms->dsize)) + goto Err; + if(mb.maxsize - mb.size + mb.free >= n && mb.nindex < mb.maxindex) + break; + lumpDecRef(u, 1); + u = nil; + } + /* add block to meta file */ + if(i == nb) { + if(!sourceSetDepth(ms, (i+1)*ms->dsize)) + goto Err; + u = sourceGetLump(ms, i, 0, 1); + if(u == nil) + goto Err; + sourceSetSize(ms, (nb+1)*ms->dsize); + mbInit(&mb, u->data, u->asize); + mbPack(&mb); + } + lumpDecRef(u, 1); + return i; +Err: + lumpDecRef(u, 1); + return NilBlock; +} + |