diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/vac/cache.c | 876 | ||||
-rw-r--r-- | src/cmd/vac/dat.h | 149 | ||||
-rw-r--r-- | src/cmd/vac/error.c | 2 | ||||
-rw-r--r-- | src/cmd/vac/error.h | 2 | ||||
-rw-r--r-- | src/cmd/vac/file.c | 2276 | ||||
-rw-r--r-- | src/cmd/vac/fns.h | 55 | ||||
-rw-r--r-- | src/cmd/vac/fs.c | 187 | ||||
-rw-r--r-- | src/cmd/vac/mkfile | 3 | ||||
-rw-r--r-- | src/cmd/vac/pack.c | 246 | ||||
-rw-r--r-- | src/cmd/vac/source.c | 390 | ||||
-rw-r--r-- | src/cmd/vac/stdinc.h | 9 | ||||
-rw-r--r-- | src/cmd/vac/vac.c | 746 | ||||
-rw-r--r-- | src/cmd/vac/vac.h | 109 | ||||
-rw-r--r-- | src/cmd/vac/vtdump.c | 215 |
14 files changed, 2365 insertions, 2900 deletions
diff --git a/src/cmd/vac/cache.c b/src/cmd/vac/cache.c deleted file mode 100644 index fc34d688..00000000 --- a/src/cmd/vac/cache.c +++ /dev/null @@ -1,876 +0,0 @@ -#include "stdinc.h" -#include "vac.h" -#include "dat.h" -#include "fns.h" - -typedef struct Label Label; - -enum { - BadHeap = ~0, -}; - -/* - * the plan is to store data to the cache in c->size blocks - * with the block zero extended to fill it out. When writing to - * venti, the block will be zero truncated. The walker will also check - * that the block fits within psize or dsize as the case may be. - */ - -struct Cache -{ - VtLock *lk; - VtSession *z; - u32int now; /* ticks for usage timestamps */ - int size; /* max. size of any block; allocated to each block */ - Lump **heads; /* hash table for finding address */ - int nheap; /* number of available victims */ - Lump **heap; /* heap for locating victims */ - long nblocks; /* number of blocks allocated */ - Lump *blocks; /* array of block descriptors */ - u8int *mem; /* memory for all block descriptors */ - Lump *free; /* free list of lumps */ - - long hashSize; -}; - -/* - * the tag for a block is hash(index, parent tag) - */ - -struct Label { - uchar gen[4]; - uchar state; - uchar type; /* top bit indicates it is part of a directory */ - uchar tag[4]; /* tag of file it is in */ -}; - - -static char ENoDir[] = "directory entry is not allocated"; - -static void fixHeap(int si, Lump *b); -static int upHeap(int i, Lump *b); -static int downHeap(int i, Lump *b); -static char *lumpState(int); -static void lumpSetState(Lump *u, int state); - -Cache * -cacheAlloc(VtSession *z, int blockSize, long nblocks) -{ - int i; - Cache *c; - Lump *b; - - c = vtMemAllocZ(sizeof(Cache)); - - c->lk = vtLockAlloc(); - c->z = z; - c->size = blockSize; - c->nblocks = nblocks; - c->hashSize = nblocks; - c->heads = vtMemAllocZ(c->hashSize*sizeof(Lump*)); - c->heap = vtMemAllocZ(nblocks*sizeof(Lump*)); - c->blocks = vtMemAllocZ(nblocks*sizeof(Lump)); - c->mem = vtMemAllocZ(nblocks * blockSize); - for(i = 0; i < nblocks; i++){ - b = &c->blocks[i]; - b->lk = vtLockAlloc(); - b->c = c; - b->data = &c->mem[i * blockSize]; - b->addr = i+1; - b->state = LumpFree; - b->heap = BadHeap; - b->next = c->free; - c->free = b; - } - c->nheap = 0; - - return c; -} - -long -cacheGetSize(Cache *c) -{ - return c->nblocks; -} - -int -cacheGetBlockSize(Cache *c) -{ - return c->size; -} - -int -cacheSetSize(Cache *c, long nblocks) -{ - USED(c); - USED(nblocks); - return 0; -} - -void -cacheFree(Cache *c) -{ - int i; - - for(i = 0; i < c->nblocks; i++){ - assert(c->blocks[i].ref == 0); - vtLockFree(c->blocks[i].lk); - } - vtMemFree(c->heads); - vtMemFree(c->blocks); - vtMemFree(c->mem); - vtMemFree(c); -} - -static u32int -hash(Cache *c, uchar score[VtScoreSize], int type) -{ - u32int h; - uchar *p = score + VtScoreSize-4; - - h = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - h += type; - return h % c->hashSize; -} - -static void -findLump(Cache *c, Lump *bb) -{ - Lump *b, *last; - int h; - - last = nil; - h = hash(c, bb->score, bb->type); - for(b = c->heads[h]; b != nil; b = b->next){ - if(last != b->prev) - vtFatal("bad prev link"); - if(b == bb) - return; - last = b; - } - vtFatal("block missing from hash table"); -} - -void -cacheCheck(Cache *c) -{ - u32int size, now; - int i, k, refed, free; - static uchar zero[VtScoreSize]; - Lump *p; - - size = c->size; - now = c->now; - - free = 0; - for(p=c->free; p; p=p->next) - free++; - for(i = 0; i < c->nheap; i++){ - if(c->heap[i]->heap != i) - vtFatal("mis-heaped at %d: %d", i, c->heap[i]->heap); - if(i > 0 && c->heap[(i - 1) >> 1]->used2 - now > c->heap[i]->used2 - now) - vtFatal("bad heap ordering"); - k = (i << 1) + 1; - if(k < c->nheap && c->heap[i]->used2 - now > c->heap[k]->used2 - now) - vtFatal("bad heap ordering"); - k++; - if(k < c->nheap && c->heap[i]->used2 - now > c->heap[k]->used2 - now) - vtFatal("bad heap ordering"); - } - - refed = 0; - for(i = 0; i < c->nblocks; i++){ - if(c->blocks[i].data != &c->mem[i * size]) - vtFatal("mis-blocked at %d", i); - if(c->blocks[i].ref && c->blocks[i].heap == BadHeap){ - refed++; - } - if(memcmp(zero, c->blocks[i].score, VtScoreSize)) - findLump(c, &c->blocks[i]); - } -if(refed > 0)fprint(2, "cacheCheck: nheap %d refed %d free %d\n", c->nheap, refed, free); - assert(c->nheap + refed + free == c->nblocks); - refed = 0; - for(i = 0; i < c->nblocks; i++){ - if(c->blocks[i].ref) { -if(1)fprint(2, "%d %V %d %s\n", c->blocks[i].type, c->blocks[i].score, c->blocks[i].ref, lumpState(c->blocks[i].state)); - refed++; - } - } -if(refed > 0)fprint(2, "cacheCheck: in used %d\n", refed); -} - -/* - * delete an arbitrary block from the heap - */ -static void -delHeap(Lump *db) -{ - fixHeap(db->heap, db->c->heap[--db->c->nheap]); - db->heap = BadHeap; -} - -static void -fixHeap(int si, Lump *b) -{ - int i; - - i = upHeap(si, b); - if(i == si) - downHeap(i, b); -} - -static int -upHeap(int i, Lump *b) -{ - Lump *bb; - u32int now; - int p; - Cache *c; - - c = b->c; - now = c->now; - for(; i != 0; i = p){ - p = (i - 1) >> 1; - bb = c->heap[p]; - if(b->used2 - now >= bb->used2 - now) - break; - c->heap[i] = bb; - bb->heap = i; - } - c->heap[i] = b; - b->heap = i; - - return i; -} - -static int -downHeap(int i, Lump *b) -{ - Lump *bb; - u32int now; - int k; - Cache *c; - - c = b->c; - now = c->now; - for(; ; i = k){ - k = (i << 1) + 1; - if(k >= c->nheap) - break; - if(k + 1 < c->nheap && c->heap[k]->used2 - now > c->heap[k + 1]->used2 - now) - k++; - bb = c->heap[k]; - if(b->used2 - now <= bb->used2 - now) - break; - c->heap[i] = bb; - bb->heap = i; - } - c->heap[i] = b; - b->heap = i; - return i; -} - - -/* called with c->lk held */ -Lump * -cacheBumpLump(Cache *c) -{ - Lump *b; - - /* - * missed: locate the block with the oldest second to last use. - * remove it from the heap, and fix up the heap. - */ - if(c->free) { - b = c->free; - c->free = b->next; - } else { - for(;;){ - if(c->nheap == 0) { - cacheCheck(c); - assert(0); - return nil; - } - b = c->heap[0]; - delHeap(b); - if(b->ref == 0) - break; - } - - /* - * unchain the block from hash chain - */ - if(b->prev == nil) - c->heads[hash(c, b->score, b->type)] = b->next; - else - b->prev->next = b->next; - if(b->next != nil) - b->next->prev = b->prev; - - } - - /* - * the new block has no last use, so assume it happens sometime in the middle - */ - b->used = (b->used2 + c->now) / 2; - b->asize = 0; - - return b; -} - -Lump * -cacheAllocLump(Cache *c, int type, int size, int dir) -{ - Lump *b; - ulong h; - - assert(size <= c->size); - -again: - vtLock(c->lk); - b = cacheBumpLump(c); - if(b == nil) { - vtUnlock(c->lk); -fprint(2, "cache is full\n"); - /* XXX should be better */ - sleep(100); - goto again; - } - - vtLock(b->lk); - - assert(b->ref == 0); - b->ref++; - b->used2 = b->used; - b->used = c->now++; - - /* convert addr into score */ - memset(b->score, 0, VtScoreSize-4); - b->score[VtScoreSize-4] = b->addr>>24; - b->score[VtScoreSize-3] = b->addr>>16; - b->score[VtScoreSize-2] = b->addr>>8; - b->score[VtScoreSize-1] = b->addr; - - b->dir = dir; - b->type = type; - b->gen = 0; - b->asize = size; - b->state = LumpFree; - - h = hash(c, b->score, b->type); - - /* chain onto correct hash */ - b->next = c->heads[h]; - c->heads[h] = b; - if(b->next != nil) - b->next->prev = b; - b->prev = nil; - - vtUnlock(c->lk); - - vtZeroExtend(type, b->data, 0, size); - lumpSetState(b, LumpActive); - - return b; -} - -int -scoreIsLocal(uchar score[VtScoreSize]) -{ - static uchar zero[VtScoreSize]; - - return memcmp(score, zero, VtScoreSize-4) == 0; -} - -Lump * -cacheGetLump(Cache *c, uchar score[VtScoreSize], int type, int size) -{ - Lump *b; - ulong h; - int n; - static uchar zero[VtScoreSize]; - - assert(size <= c->size); - - h = hash(c, score, type); - -again: - /* - * look for the block in the cache - */ - vtLock(c->lk); - for(b = c->heads[h]; b != nil; b = b->next){ - if(memcmp(b->score, score, VtScoreSize) == 0 && b->type == type) - goto found; - } - - /* should not be looking for a temp block */ - if(scoreIsLocal(score)) { - if(memcmp(score, zero, VtScoreSize) == 0) - vtSetError("looking for zero score"); - else - vtSetError("missing local block"); - vtUnlock(c->lk); - return nil; - } - - b = cacheBumpLump(c); - if(b == nil) { - vtUnlock(c->lk); - sleep(100); - goto again; - } - - /* chain onto correct hash */ - b->next = c->heads[h]; - c->heads[h] = b; - if(b->next != nil) - b->next->prev = b; - b->prev = nil; - - memmove(b->score, score, VtScoreSize); - b->type = type; - b->state = LumpFree; - -found: - b->ref++; - b->used2 = b->used; - b->used = c->now++; - if(b->heap != BadHeap) - fixHeap(b->heap, b); - - vtUnlock(c->lk); - - vtLock(b->lk); - if(b->state != LumpFree) - return b; - - n = vtRead(c->z, score, type, b->data, size); - if(n < 0) { - lumpDecRef(b, 1); - return nil; - } - if(!vtSha1Check(score, b->data, n)) { - vtSetError("vtSha1Check failed"); - lumpDecRef(b, 1); - return nil; - } - vtZeroExtend(type, b->data, n, size); - b->asize = size; - lumpSetState(b, LumpVenti); - - return b; -} - -static char * -lumpState(int state) -{ - switch(state) { - default: - return "Unknown!!"; - case LumpFree: - return "Free"; - case LumpActive: - return "Active"; - case LumpSnap: - return "Snap"; - case LumpZombie: - return "Zombie"; - case LumpVenti: - return "Venti"; - } -} - -static void -lumpSetState(Lump *u, int state) -{ -// if(u->state != LumpFree) -// fprint(2, "%V: %s -> %s\n", u->score, lumpState(u->state), lumpState(state)); - u->state = state; -} - -int -lumpGetScore(Lump *u, int offset, uchar score[VtScoreSize]) -{ - uchar *sp; - VtRoot root; - VtEntry dir; - - vtLock(u->lk); - - switch(u->type) { - default: - vtSetError("bad type"); - goto Err; - case VtPointerType0: - case VtPointerType1: - case VtPointerType2: - case VtPointerType3: - case VtPointerType4: - case VtPointerType5: - case VtPointerType6: - if((offset+1)*VtScoreSize > u->asize) - sp = nil; - else - sp = u->data + offset*VtScoreSize; - break; - case VtRootType: - if(u->asize < VtRootSize) { - vtSetError("runt root block"); - goto Err; - } - if(!vtRootUnpack(&root, u->data)) - goto Err; - sp = root.score; - break; - case VtDirType: - if((offset+1)*VtEntrySize > u->asize) { - vtSetError(ENoDir); - goto Err; - } - if(!vtEntryUnpack(&dir, u->data, offset)) - goto Err; - if(!dir.flags & VtEntryActive) { - vtSetError(ENoDir); - goto Err; - } - sp = dir.score; - break; - } - - if(sp == nil) - memmove(score, vtZeroScore, VtScoreSize); - else - memmove(score, sp, VtScoreSize); - - vtUnlock(u->lk); - return !scoreIsLocal(score); -Err: - vtUnlock(u->lk); - return 0; -} - -Lump * -lumpWalk(Lump *u, int offset, int type, int size, int readOnly, int lock) -{ - Lump *v, *vv; - Cache *c; - uchar score[VtScoreSize], *sp; - VtRoot root; - VtEntry dir; - int split, isdir; - - c = u->c; - vtLock(u->lk); - -Again: - v = nil; - vv = nil; - - isdir = u->dir; - switch(u->type) { - default: - vtSetError("bad type"); - goto Err; - case VtPointerType0: - case VtPointerType1: - case VtPointerType2: - case VtPointerType3: - case VtPointerType4: - case VtPointerType5: - case VtPointerType6: - if((offset+1)*VtScoreSize > u->asize) - sp = nil; - else - sp = u->data + offset*VtScoreSize; - break; - case VtRootType: - if(u->asize < VtRootSize) { - vtSetError("runt root block"); - goto Err; - } - if(!vtRootUnpack(&root, u->data)) - goto Err; - sp = root.score; - break; - case VtDirType: - if((offset+1)*VtEntrySize > u->asize) { - vtSetError(ENoDir); - goto Err; - } - if(!vtEntryUnpack(&dir, u->data, offset)) - goto Err; - if(!(dir.flags & VtEntryActive)) { - vtSetError(ENoDir); - goto Err; - } - isdir = (dir.flags & VtEntryDir) != 0; -// sp = dir.score; - sp = u->data + offset*VtEntrySize + 20; - break; - } - - if(sp == nil) - memmove(score, vtZeroScore, VtScoreSize); - else - memmove(score, sp, VtScoreSize); - - vtUnlock(u->lk); - - -if(0)fprint(2, "lumpWalk: %V:%s %d:%d-> %V:%d\n", u->score, lumpState(u->state), u->type, offset, score, type); - v = cacheGetLump(c, score, type, size); - if(v == nil) - return nil; - - split = 1; - if(readOnly) - split = 0; - - switch(v->state) { - default: - assert(0); - case LumpFree: -fprint(2, "block is free %V!\n", v->score); - vtSetError("phase error"); - goto Err2; - case LumpActive: - if(v->gen < u->gen) { -print("LumpActive gen\n"); - lumpSetState(v, LumpSnap); - v->gen = u->gen; - } else - split = 0; - break; - case LumpSnap: - case LumpVenti: - break; - } - - /* easy case */ - if(!split) { - if(!lock) - vtUnlock(v->lk); - return v; - } - - if(sp == nil) { - vtSetError("bad offset"); - goto Err2; - } - - vv = cacheAllocLump(c, v->type, size, isdir); - /* vv is locked */ - vv->gen = u->gen; - memmove(vv->data, v->data, v->asize); -if(0)fprint(2, "split %V into %V\n", v->score, vv->score); - - lumpDecRef(v, 1); - v = nil; - - vtLock(u->lk); - if(u->state != LumpActive) { - vtSetError("bad parent state: can not happen"); - goto Err; - } - - /* check that nothing changed underfoot */ - if(memcmp(sp, score, VtScoreSize) != 0) { - lumpDecRef(vv, 1); -fprint(2, "lumpWalk: parent changed under foot\n"); - goto Again; - } - - /* XXX - hold Active blocks up - will go eventually */ - lumpIncRef(vv); - - /* change the parent */ - memmove(sp, vv->score, VtScoreSize); - - vtUnlock(u->lk); - - if(!lock) - vtUnlock(vv->lk); - return vv; -Err: - vtUnlock(u->lk); - lumpDecRef(v, 0); - lumpDecRef(vv, 1); - return nil; -Err2: - lumpDecRef(v, 1); - return nil; - -} - -void -lumpFreeEntry(Lump *u, int entry) -{ - uchar score[VtScoreSize]; - int type; - ulong gen; - VtEntry dir; - Cache *c; - - c = u->c; - vtLock(u->lk); - if(u->state == LumpVenti) - goto Exit; - - switch(u->type) { - default: - fprint(2, "freeing bad lump type: %d\n", u->type); - return; - case VtPointerType0: - if((entry+1)*VtScoreSize > u->asize) - goto Exit; - memmove(score, u->data + entry*VtScoreSize, VtScoreSize); - memmove(u->data + entry*VtScoreSize, vtZeroScore, VtScoreSize); - type = u->dir?VtDirType:VtDataType; - break; - case VtPointerType1: - case VtPointerType2: - case VtPointerType3: - case VtPointerType4: - case VtPointerType5: - case VtPointerType6: - if((entry+1)*VtScoreSize > u->asize) - goto Exit; - memmove(score, u->data + entry*VtScoreSize, VtScoreSize); - memmove(u->data + entry*VtScoreSize, vtZeroScore, VtScoreSize); - type = u->type-1; - break; - case VtDirType: - if((entry+1)*VtEntrySize > u->asize) - goto Exit; - if(!vtEntryUnpack(&dir, u->data, entry)) - goto Exit; - if(!dir.flags & VtEntryActive) - goto Exit; - gen = dir.gen; - if(gen != ~0) - gen++; - if(dir.depth == 0) - type = (dir.flags&VtEntryDir)?VtDirType:VtDataType; - else - type = VtPointerType0 + dir.depth - 1; - memmove(score, dir.score, VtScoreSize); - memset(&dir, 0, sizeof(dir)); - dir.gen = gen; - vtEntryPack(&dir, u->data, entry); - break; - case VtDataType: - type = VtErrType; - break; - } - vtUnlock(u->lk); - if(type == VtErrType || !scoreIsLocal(score)) - return; - - u = cacheGetLump(c, score, type, c->size); - if(u == nil) - return; - lumpDecRef(u, 1); - /* XXX remove extra reference */ - lumpDecRef(u, 0); - return; -Exit: - vtUnlock(u->lk); - return; - -} - -void -lumpCleanup(Lump *u) -{ - int i, n; - - switch(u->type) { - default: - return; - case VtPointerType0: - case VtPointerType1: - case VtPointerType2: - case VtPointerType3: - case VtPointerType4: - case VtPointerType5: - case VtPointerType6: - n = u->asize/VtScoreSize; - break; - case VtDirType: - n = u->asize/VtEntrySize; - break; - } - - for(i=0; i<n; i++) - lumpFreeEntry(u, i); -} - - -void -lumpDecRef(Lump *b, int unlock) -{ - int i; - Cache *c; - - if(b == nil) - return; - - if(unlock) - vtUnlock(b->lk); - - c = b->c; - vtLock(c->lk); - if(--b->ref > 0) { - vtUnlock(c->lk); - return; - } - assert(b->ref == 0); - - switch(b->state) { - default: - fprint(2, "bad state: %s\n", lumpState(b->state)); - assert(0); - case LumpActive: - /* hack - but will do for now */ - b->ref++; - vtUnlock(c->lk); - lumpCleanup(b); - vtLock(c->lk); - b->ref--; - lumpSetState(b, LumpFree); - break; - case LumpZombie: - lumpSetState(b, LumpFree); - break; - case LumpFree: - case LumpVenti: - break; - } - - /* - * reinsert in the free heap - */ - if(b->heap == BadHeap) { - i = upHeap(c->nheap++, b); - c->heap[i] = b; - b->heap = i; - } - - vtUnlock(c->lk); -} - -Lump * -lumpIncRef(Lump *b) -{ - Cache *c; - - c = b->c; - - vtLock(c->lk); - assert(b->ref > 0); - b->ref++; - vtUnlock(c->lk); - return b; -} diff --git a/src/cmd/vac/dat.h b/src/cmd/vac/dat.h index a468668d..ec15db4a 100644 --- a/src/cmd/vac/dat.h +++ b/src/cmd/vac/dat.h @@ -1,60 +1,27 @@ -typedef struct Source Source; -typedef struct VacFile VacFile; typedef struct MetaBlock MetaBlock; typedef struct MetaEntry MetaEntry; -typedef struct Lump Lump; -typedef struct Cache Cache; -typedef struct Super Super; -enum { - NilBlock = (~0UL), +enum +{ MaxBlock = (1UL<<31), }; - -struct VacFS { - int ref; - - /* need a read write lock? */ - - uchar score[VtScoreSize]; - VacFile *root; - - VtSession *z; - int readOnly; - int bsize; /* maximum block size */ - uvlong qid; /* next qid */ - Cache *cache; +enum { + BytesPerEntry = 100, /* estimate of bytes per dir entries - determines number of index entries in the block */ + FullPercentage = 80, /* don't allocate in block if more than this percentage full */ + FlushSize = 200, /* number of blocks to flush */ + DirtyPercentage = 50, /* maximum percentage of dirty blocks */ }; -struct Source { - VtLock *lk; - - Cache *cache; /* immutable */ - int readOnly; /* immutable */ - - Lump *lump; /* lump containing venti dir entry */ - ulong block; /* block number within parent: immutable */ - int entry; /* which entry in the block: immutable */ - - /* most of a VtEntry, except the score */ - ulong gen; /* generation: immutable */ - int dir; /* dir flags: immutable */ - int depth; /* number of levels of pointer blocks */ - int psize; /* pointer block size: immutable */ - int dsize; /* data block size: immutable */ - uvlong size; /* size in bytes of file */ - - int epb; /* dir entries per block = dize/VtEntrySize: immutable */ -}; - -struct MetaEntry { +struct MetaEntry +{ uchar *p; ushort size; }; -struct MetaBlock { +struct MetaBlock +{ int maxsize; /* size of block */ int size; /* size used */ int free; /* free space within used size */ @@ -64,93 +31,13 @@ struct MetaBlock { uchar *buf; }; -/* - * contains a one block buffer - * to avoid problems of the block changing underfoot - * and to enable an interface that supports unget. - */ -struct VacDirEnum { +struct VacDirEnum +{ VacFile *file; - - ulong block; /* current block */ - MetaBlock mb; /* parsed version of block */ - int index; /* index in block */ -}; - -/* Lump states */ -enum { - LumpFree, - LumpVenti, /* on venti server: score > 2^32: just a cached copy */ - LumpActive, /* active */ - LumpActiveRO, /* active: read only block */ - LumpActiveA, /* active: achrived */ - LumpSnap, /* snapshot: */ - LumpSnapRO, /* snapshot: read only */ - LumpSnapA, /* snapshot: achived */ - LumpZombie, /* block with no pointer to it: waiting to be freed */ - - LumpMax -}; - -/* - * Each lump has a state and generation - * The following invariants are maintained - * Each lump has no more than than one parent per generation - * For Active*, no child has a parent of a greater generation - * For Snap*, there is a snap parent of given generation and there are - * no parents of greater gen - implies no children of a greater gen - * For *RO, the lump is fixed - no change ca be made - all pointers - * are valid venti addresses - * For *A, the lump is on the venti server - * There are no pointers to Zombie lumps - * - * Transitions - * Archiver at generation g - * Mutator at generation h - * - * Want to modify a lump - * Venti: create new Active(h) - * Active(x): x == h: do nothing - * Acitve(x): x < h: change to Snap(h-1) + add Active(h) - * ActiveRO(x): change to SnapRO(h-1) + add Active(h) - * ActiveA(x): add Active(h) - * Snap*(x): should not occur - * Zombie(x): should not occur - * Want to archive - * Active(x): x != g: should never happen - * Active(x): x == g fix children and free them: move to ActoveRO(g); - * ActiveRO(x): x != g: should never happen - * ActiveRO(x): x == g: wait until it hits ActiveA or SnapA - * ActiveA(x): done - * Active(x): x < g: should never happen - * Snap(x): x >= g: fix children, freeing all SnapA(y) x == y; - * SnapRO(x): wait until it hits SnapA - * - */ - - -struct Lump { - int ref; - - Cache *c; - - VtLock *lk; - - int state; - ulong gen; - - uchar *data; - uchar score[VtScoreSize]; /* score of packet */ - uchar vscore[VtScoreSize]; /* venti score - when archived */ - u8int type; /* type of packet */ - int dir; /* part of a directory - extension of type */ - u16int asize; /* allocated size of block */ - Lump *next; /* doubly linked hash chains */ - Lump *prev; - u32int heap; /* index in heap table */ - u32int used; /* last reference times */ - u32int used2; - - u32int addr; /* mutable block address */ + u32int boff; + int i, n; + VacDir *buf; }; +void _mbinit(MetaBlock*, u8int*, uint, uint); +int _mbsearch(MetaBlock*, char*, int*, MetaEntry*); diff --git a/src/cmd/vac/error.c b/src/cmd/vac/error.c index 5c8ff29d..f28f9376 100644 --- a/src/cmd/vac/error.c +++ b/src/cmd/vac/error.c @@ -5,6 +5,8 @@ #include "error.h" char ENoDir[] = "directory entry is not allocated"; +char ENoFile[] = "no such file or directory"; +char EBadPath[] = "bad path"; char EBadDir[] = "corrupted directory entry"; char EBadMeta[] = "corrupted meta data"; char ENotDir[] = "not a directory"; diff --git a/src/cmd/vac/error.h b/src/cmd/vac/error.h index 742228cf..bbb97373 100644 --- a/src/cmd/vac/error.h +++ b/src/cmd/vac/error.h @@ -12,3 +12,5 @@ extern char ERemoved[]; extern char ENotEmpty[]; extern char EExists[]; extern char ERoot[]; +extern char ENoFile[]; +extern char EBadPath[]; diff --git a/src/cmd/vac/file.c b/src/cmd/vac/file.c index 900422d2..cdcfd50a 100644 --- a/src/cmd/vac/file.c +++ b/src/cmd/vac/file.c @@ -8,382 +8,150 @@ * locking order is upwards. A thread can hold the lock for a VacFile * and then acquire the lock of its parent */ +struct VacFile +{ + VacFs *fs; /* immutable */ -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 */ + int ref; /* holds this data structure up */ + + int partial; /* file was never really open */ + int removed; /* file has been removed */ + int dirty; /* dir is dirty with respect to meta data in block */ + u32int boff; /* block offset within msource for this file's metadata */ + VacDir dir; /* metadata for this file */ + VacFile *up; /* parent file */ + VacFile *next; /* sibling */ + + RWLock lk; /* lock for the following */ + VtFile *source; /* actual data */ + VtFile *msource; /* metadata for children in a directory */ + VacFile *down; /* children */ + int mode; }; -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) +static int filelock(VacFile*); +static u32int filemetaalloc(VacFile*, VacDir*, u32int); +static int filemetaflush2(VacFile*, char*); +static void filemetalock(VacFile*); +static void filemetaunlock(VacFile*); +static void fileraccess(VacFile*); +static int filerlock(VacFile*); +static void filerunlock(VacFile*); +static void fileunlock(VacFile*); +static void filewaccess(VacFile*, char*); + +void mbinit(MetaBlock*, u8int*, uint, uint); +int mbsearch(MetaBlock*, char*, int*, MetaEntry*); +int mbresize(MetaBlock*, MetaEntry*, int); +VacFile *vdlookup(VacFile*, char*); + +static VacFile* +filealloc(VacFs *fs) { - vfMetaLock(vf); - vf->dir.atime = time(0L); - vf->dirty = 1; - vfMetaUnlock(vf); - vfMetaFlush(vf); + VacFile *f; + + f = vtmallocz(sizeof(VacFile)); + f->ref = 1; + f->fs = fs; + f->boff = NilBlock; + f->mode = fs->mode; + return f; } 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) +filefree(VacFile *f) { - *dst = *src; - dst->elem = vtStrDup(src->elem); - dst->uid = vtStrDup(src->uid); - dst->gid = vtStrDup(src->gid); - dst->mid = vtStrDup(src->mid); + vtfileclose(f->source); + vtfileclose(f->msource); + vdcleanup(&f->dir); + memset(f, ~0, sizeof *f); /* paranoia */ + vtfree(f); } -static int -mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me) +/* + * the file is locked already + * f->msource is unlocked + */ +static VacFile* +dirlookup(VacFile *f, char *elem) { 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)) + VtBlock *b; + VtFile *meta; + VacFile *ff; + u32int bo, nb; + + meta = f->msource; + b = nil; + if(vtfilelock(meta, -1) < 0) + return nil; + nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize; + for(bo=0; bo<nb; bo++){ + b = vtfileblock(meta, bo, VtOREAD); + if(b == nil) goto Err; - if(!mbSearch(&mb, elem, &j, &me)) + if(mbunpack(&mb, b->data, meta->dsize) < 0) goto Err; - if(me.p != nil) { - nvf = vfAlloc(vf->fs); - if(!vdUnpack(&nvf->dir, &me)) { - vfFree(nvf); + if(mbsearch(&mb, elem, &i, &me) < 0){ + ff = filealloc(f->fs); + if(vdunpack(&ff->dir, &me) < 0){ + filefree(ff); goto Err; } - lumpDecRef(u, 1); - nvf->block = i; - return nvf; + vtfileunlock(meta); + vtblockput(b); + ff->boff = bo; + ff->mode = f->mode; + return ff; } - - lumpDecRef(u, 1); - u = nil; + + vtblockput(b); + b = nil; } - vtSetError("file does not exist"); + werrstr(ENoFile); /* fall through */ Err: - lumpDecRef(u, 1); + vtfileunlock(meta); + vtblockput(b); return nil; } -VacFile * -vfRoot(VacFS *fs, uchar *score) +VacFile* +_vacfileroot(VacFs *fs, VtFile *r) { - VtEntry e; - Lump *u, *v; - Source *r, *r0, *r1, *r2; + VtBlock *b; + VtFile *r0, *r1, *r2; MetaBlock mb; MetaEntry me; VacFile *root, *mr; + b = nil; 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) + if(vtfilelock(r, -1) < 0) + return nil; + r0 = vtfileopen(r, 0, fs->mode); + if(r0 == 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) + r1 = vtfileopen(r, 1, fs->mode); + if(r1 == nil) + goto Err; + r2 = vtfileopen(r, 2, fs->mode); + if(r2 == nil) goto Err; - mr = vfAlloc(fs); + mr = filealloc(fs); mr->msource = r2; r2 = nil; - root = vfAlloc(fs); + root = filealloc(fs); + root->boff = 0; root->up = mr; root->source = r0; r0 = nil; @@ -392,280 +160,404 @@ vfRoot(VacFS *fs, uchar *score) mr->down = root; - if(!mbUnpack(&mb, u->data, u->asize)) + if(vtfilelock(mr->msource, -1) < 0) goto Err; - - if(!meUnpack(&me, &mb, 0)) + b = vtfileblock(mr->msource, 0, VtOREAD); + vtfileunlock(mr->msource); + if(b == nil) goto Err; - if(!vdUnpack(&root->dir, &me)) + + if(mbunpack(&mb, b->data, mr->msource->dsize) < 0) goto Err; - vfRAccess(root); - lumpDecRef(u, 0); - sourceFree(r2); + meunpack(&me, &mb, 0); + if(vdunpack(&root->dir, &me) < 0) + goto Err; + vtblockput(b); + vtfileunlock(r); + fileraccess(root); return root; Err: - lumpDecRef(u, 0); - lumpDecRef(v, 0); + vtblockput(b); if(r0) - sourceFree(r0); + vtfileclose(r0); if(r1) - sourceFree(r1); + vtfileclose(r1); if(r2) - sourceFree(r2); - if(r) - sourceFree(r); + vtfileclose(r2); if(mr) - vfFree(mr); + filefree(mr); if(root) - vfFree(root); + filefree(root); + vtfileunlock(r); + + return nil; +} +static VtFile * +fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode) +{ + VtFile *r; + + if(vtfilelock(f->source, mode) < 0) + return nil; + r = vtfileopen(f->source, offset, mode); + vtfileunlock(f->source); + if(r == nil) + return nil; + if(r->gen != gen){ + werrstr(ERemoved); + goto Err; + } + if(r->dir != dir && r->mode != -1){ +fprint(2, "fileopensource: dir mismatch %d %d\n", r->dir, dir); + werrstr(EBadMeta); + goto Err; + } + return r; +Err: + vtfileclose(r); return nil; } -VacFile * -vfWalk(VacFile *vf, char *elem) +VacFile* +_filewalk(VacFile *f, char *elem, int partial) { - VacFile *nvf; + VacFile *ff; - vfRAccess(vf); + fileraccess(f); - if(elem[0] == 0) { - vtSetError("illegal path element"); + if(elem[0] == 0){ + werrstr(EBadPath); return nil; } - if(!vfIsDir(vf)) { - vtSetError("not a directory"); + + if(!vacfileisdir(f)){ + werrstr(ENotDir); return nil; } - if(strcmp(elem, ".") == 0) { - return vfIncRef(vf); + if(strcmp(elem, ".") == 0){ + return vacfileincref(f); } - if(strcmp(elem, "..") == 0) { - if(vfIsRoot(vf)) - return vfIncRef(vf); - return vfIncRef(vf->up); + if(strcmp(elem, "..") == 0){ + if(vacfileisroot(f)) + return vacfileincref(f); + return vacfileincref(f->up); } - if(!vfLock(vf)) + if(filelock(f) < 0) return nil; - for(nvf = vf->down; nvf; nvf=nvf->next) { - if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) { - nvf->ref++; + for(ff = f->down; ff; ff=ff->next){ + if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ + ff->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) + ff = dirlookup(f, elem); + if(ff == nil) goto Err; - if(nvf->dir.mode & ModeDir) { - nvf->msource = sourceOpen(vf->source, nvf->dir.mentry, vf->fs->readOnly); - if(nvf->msource == nil) + + if(ff->dir.mode & ModeSnapshot) + ff->mode = VtOREAD; + + if(partial){ + /* + * Do nothing. We're opening this file only so we can clri it. + * Usually the sources can't be opened, hence we won't even bother. + * Be VERY careful with the returned file. If you hand it to a routine + * expecting ff->source and/or ff->msource to be non-nil, we're + * likely to dereference nil. FileClri should be the only routine + * setting partial. + */ + ff->partial = 1; + }else if(ff->dir.mode & ModeDir){ + ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode); + ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode); + if(ff->source == nil || ff->msource == nil) + goto Err; + }else{ + ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode); + if(ff->source == nil) goto Err; } /* link in and up parent ref count */ - nvf->next = vf->down; - vf->down = nvf; - nvf->up = vf; - vfIncRef(vf); + ff->next = f->down; + f->down = ff; + ff->up = f; + vacfileincref(f); Exit: - vfUnlock(vf); - return nvf; + fileunlock(f); + return ff; Err: - vfUnlock(vf); - if(nvf != nil) - vfFree(nvf); + fileunlock(f); + if(ff != nil) + vacfiledecref(ff); return nil; } -VacFile * -vfOpen(VacFS *fs, char *path) +VacFile* +vacfilewalk(VacFile *f, char *elem) { - VacFile *vf, *nvf; - char *p, elem[VtMaxStringSize]; + return _filewalk(f, elem, 0); +} + +VacFile* +_fileopen(VacFs *fs, char *path, int partial) +{ + VacFile *f, *ff; + char *p, elem[VtMaxStringSize], *opath; int n; - vf = fs->root; - vfIncRef(vf); - while(*path != 0) { + f = fs->root; + vacfileincref(f); + opath = path; + while(*path != 0){ for(p = path; *p && *p != '/'; p++) ; n = p - path; - if(n > 0) { - if(n > VtMaxStringSize) { - vtSetError("path element too long"); + if(n > 0){ + if(n > VtMaxStringSize){ + werrstr("%s: element too long", EBadPath); goto Err; } memmove(elem, path, n); elem[n] = 0; - nvf = vfWalk(vf, elem); - if(nvf == nil) + ff = _filewalk(f, elem, partial && *p=='\0'); + if(ff == nil){ + werrstr("%.*s: %R", utfnlen(opath, p-opath), opath); goto Err; - vfDecRef(vf); - vf = nvf; + } + vacfiledecref(f); + f = ff; } if(*p == '/') p++; path = p; } - return vf; + return f; Err: - vfDecRef(vf); + vacfiledecref(f); return nil; } -VacFile * -vfCreate(VacFile *vf, char *elem, ulong mode, char *user) +VacFile* +vacfileopen(VacFs *fs, char *path) { - VacFile *nvf; + return _fileopen(fs, path, 0); +} + +#if 0 +static void +filesettmp(VacFile *f, int istmp) +{ + int i; + VtEntry e; + VtFile *r; + + for(i=0; i<2; i++){ + if(i==0) + r = f->source; + else + r = f->msource; + if(r == nil) + continue; + if(vtfilegetentry(r, &e) < 0){ + fprint(2, "vtfilegetentry failed (cannot happen): %r\n"); + continue; + } + if(istmp) + e.flags |= VtEntryNoArchive; + else + e.flags &= ~VtEntryNoArchive; + if(vtfilesetentry(r, &e) < 0){ + fprint(2, "vtfilesetentry failed (cannot happen): %r\n"); + continue; + } + } +} +#endif + +VacFile* +vacfilecreate(VacFile *f, char *elem, ulong mode, char *uid) +{ + VacFile *ff; VacDir *dir; - int n, i; - uchar *p; - Source *pr, *r, *mr; + VtFile *pr, *r, *mr; int isdir; - MetaBlock mb; - MetaEntry me; - Lump *u; - if(!vfLock(vf)) + if(filelock(f) < 0) 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; + for(ff = f->down; ff; ff=ff->next){ + if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ + ff = nil; + werrstr(EExists); + goto Err1; } } - nvf = dirLookup(vf, elem); - if(nvf != nil) { - vtSetError(EExists); - goto Err; + ff = dirlookup(f, elem); + if(ff != nil){ + werrstr(EExists); + goto Err1; + } + + pr = f->source; + if(pr->mode != VtORDWR){ + werrstr(EReadOnly); + goto Err1; } - nvf = vfAlloc(vf->fs); + if(vtfilelock2(f->source, f->msource, -1) < 0) + goto Err1; + + ff = filealloc(f->fs); isdir = mode & ModeDir; - pr = vf->source; - r = sourceCreate(pr, pr->psize, pr->dsize, isdir, 0); + r = vtfilecreate(pr, 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(isdir){ + mr = vtfilecreate(pr, pr->dsize, 0, r->offset); if(mr == nil) goto Err; } - - dir = &nvf->dir; - dir->elem = vtStrDup(elem); - dir->entry = r->block*pr->epb + r->entry; + + dir = &ff->dir; + dir->elem = vtstrdup(elem); + dir->entry = r->offset; dir->gen = r->gen; - if(isdir) { - dir->mentry = mr->block*pr->epb + mr->entry; + if(isdir){ + dir->mentry = mr->offset; 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); + if(_vacfsnextqid(f->fs, &dir->qid) < 0) + goto Err; + dir->uid = vtstrdup(uid); + dir->gid = vtstrdup(f->dir.gid); + dir->mid = vtstrdup(uid); 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)) + ff->boff = filemetaalloc(f, dir, 0); + if(ff->boff == NilBlock) 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); + vtfileunlock(f->source); + vtfileunlock(f->msource); - nvf->source = r; - nvf->msource = mr; + ff->source = r; + ff->msource = mr; + +#if 0 + if(mode&ModeTemporary){ + if(vtfilelock2(r, mr, -1) < 0) + goto Err1; + filesettmp(ff, 1); + vtfileunlock(r); + if(mr) + vtfileunlock(mr); + } +#endif + + /* committed */ /* link in and up parent ref count */ - nvf->next = vf->down; - vf->down = nvf; - nvf->up = vf; - vfIncRef(vf); + ff->next = f->down; + f->down = ff; + ff->up = f; + vacfileincref(f); - vfWAccess(vf, user); + filewaccess(f, uid); - vfUnlock(vf); - return nvf; + fileunlock(f); + return ff; Err: - lumpDecRef(u, 1); - if(r) - sourceRemove(r); - if(mr) - sourceRemove(mr); - if(nvf) - vfFree(nvf); - vfUnlock(vf); - return 0; + vtfileunlock(f->source); + vtfileunlock(f->msource); +Err1: + if(r){ + vtfilelock(r, -1); + vtfileremove(r); + } + if(mr){ + vtfilelock(mr, -1); + vtfileremove(mr); + } + if(ff) + vacfiledecref(ff); + fileunlock(f); + return nil; } +int +vacfileblockscore(VacFile *f, u32int bn, u8int *score) +{ + VtFile *s; + uvlong size; + int dsize, ret; + + ret = -1; + if(filerlock(f) < 0) + return -1; + fileraccess(f); + if(vtfilelock(f->source, VtOREAD) < 0) + goto out; + + s = f->source; + dsize = s->dsize; + size = vtfilegetsize(s); + if((uvlong)bn*dsize >= size) + goto out; + ret = vtfileblockscore(f->source, bn, score); + +out: + vtfileunlock(f->source); + filerunlock(f); + return ret; +} int -vfRead(VacFile *vf, void *buf, int cnt, vlong offset) +vacfileread(VacFile *f, void *buf, int cnt, vlong offset) { - Source *s; + VtFile *s; uvlong size; - ulong bn; + u32int bn; int off, dsize, n, nn; - Lump *u; - uchar *b; + VtBlock *b; + uchar *p; -if(0)fprint(2, "vfRead: %s %d, %lld\n", vf->dir.elem, cnt, offset); +if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset); - if(!vfRLock(vf)) + if(filerlock(f) < 0) return -1; - s = vf->source; + if(offset < 0){ + werrstr(EBadOffset); + goto Err1; + } - dsize = s->dsize; - size = sourceGetSize(s); + fileraccess(f); - if(offset < 0) { - vtSetError(EBadOffset); - goto Err; - } + if(vtfilelock(f->source, VtOREAD) < 0) + goto Err1; - vfRAccess(vf); + s = f->source; + dsize = s->dsize; + size = vtfilegetsize(s); if(offset >= size) offset = size; @@ -674,541 +566,1269 @@ if(0)fprint(2, "vfRead: %s %d, %lld\n", vf->dir.elem, cnt, 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); + p = buf; + while(cnt > 0){ + b = vtfileblock(s, bn, OREAD); + if(b == nil) goto Err; - } n = cnt; if(n > dsize-off) n = dsize-off; - nn = u->asize-off; + nn = dsize-off; if(nn > n) nn = n; - memmove(b, u->data+off, nn); - memset(b+nn, 0, n-nn); + memmove(p, b->data+off, nn); + memset(p+nn, 0, nn-n); off = 0; bn++; cnt -= n; - b += n; - lumpDecRef(u, 0); + p += n; + vtblockput(b); } - vfRUnlock(vf); - return b-(uchar*)buf; + vtfileunlock(s); + filerunlock(f); + return p-(uchar*)buf; + Err: - vfRUnlock(vf); + vtfileunlock(s); +Err1: + filerunlock(f); return -1; } +#if 0 +/* + * Changes the file block bn to be the given block score. + * Very sneaky. Only used by flfmt. + */ +int +filemapblock(VacFile *f, ulong bn, uchar score[VtScoreSize], ulong tag) +{ + VtBlock *b; + VtEntry e; + VtFile *s; + + if(filelock(f) < 0) + return -1; + + s = nil; + if(f->dir.mode & ModeDir){ + werrstr(ENotFile); + goto Err; + } + + if(f->source->mode != VtORDWR){ + werrstr(EReadOnly); + goto Err; + } + + if(vtfilelock(f->source, -1) < 0) + goto Err; + + s = f->source; + b = _vtfileblock(s, bn, VtORDWR, 1, tag); + if(b == nil) + goto Err; + + if(vtfilegetentry(s, &e) < 0) + goto Err; + if(b->l.type == BtDir){ + memmove(e.score, score, VtScoreSize); + assert(e.tag == tag || e.tag == 0); + e.tag = tag; + e.flags |= VtEntryLocal; + vtentrypack(&e, b->data, f->source->offset % f->source->epb); + }else + memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize); + vtblockdirty(b); + vtblockput(b); + vtfileunlock(s); + fileunlock(f); + return 0; + +Err: + if(s) + vtfileunlock(s); + fileunlock(f); + return -1; +} +#endif + +int +vacfilesetsize(VacFile *f, uvlong size) +{ + int r; + + if(filelock(f) < 0) + return -1; + r = 0; + if(f->dir.mode & ModeDir){ + werrstr(ENotFile); + goto Err; + } + if(f->source->mode != VtORDWR){ + werrstr(EReadOnly); + goto Err; + } + if(vtfilelock(f->source, -1) < 0) + goto Err; + r = vtfilesetsize(f->source, size); + vtfileunlock(f->source); +Err: + fileunlock(f); + return r; +} + int -vfWrite(VacFile *vf, void *buf, int cnt, vlong offset, char *user) +filewrite(VacFile *f, void *buf, int cnt, vlong offset, char *uid) { - Source *s; + VtFile *s; ulong bn; int off, dsize, n; - Lump *u; - uchar *b; + VtBlock *b; + uchar *p; + vlong eof; - USED(user); +if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset); - if(!vfLock(vf)) + if(filelock(f) < 0) return -1; - if(vf->fs->readOnly) { - vtSetError(EReadOnly); + s = nil; + if(f->dir.mode & ModeDir){ + werrstr(ENotFile); goto Err; } - if(vf->dir.mode & ModeDir) { - vtSetError(ENotFile); + if(f->source->mode != VtORDWR){ + werrstr(EReadOnly); 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); + if(offset < 0){ + werrstr(EBadOffset); goto Err; } - vfWAccess(vf, user); + filewaccess(f, uid); + + if(vtfilelock(f->source, -1) < 0) + goto Err; + s = f->source; + dsize = s->dsize; + eof = vtfilegetsize(s); + if(f->dir.mode & ModeAppend) + offset = eof; bn = offset/dsize; off = offset%dsize; - b = buf; - while(cnt > 0) { + p = 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); + b = vtfileblock(s, bn, n<dsize?VtORDWR:VtOWRITE); + if(b == nil){ + if(offset > eof) + vtfilesetsize(s, offset); goto Err; } - memmove(u->data+off, b, n); + memmove(b->data+off, p, n); off = 0; cnt -= n; - b += n; + p += n; offset += n; bn++; - lumpDecRef(u, 0); - if(!sourceSetSize(s, offset)) - goto Err; + vtblockdirty(b); + vtblockput(b); } - vfLock(vf); - return b-(uchar*)buf; + if(offset > eof && vtfilesetsize(s, offset) < 0) + goto Err; + vtfileunlock(s); + fileunlock(f); + return p-(uchar*)buf; Err: - vfLock(vf); + if(s) + vtfileunlock(s); + fileunlock(f); return -1; } int -vfGetDir(VacFile *vf, VacDir *dir) +vacfilegetdir(VacFile *f, VacDir *dir) { - if(!vfRLock(vf)) - return 0; + if(filerlock(f) < 0) + return -1; - vfMetaLock(vf); - vdCopy(dir, &vf->dir); - vfMetaUnlock(vf); + filemetalock(f); + vdcopy(dir, &f->dir); + filemetaunlock(f); - if(!vfIsDir(vf)) - dir->size = sourceGetSize(vf->source); - vfRUnlock(vf); + if(vacfileisdir(f) < 0){ + if(vtfilelock(f->source, VtOREAD) < 0){ + filerunlock(f); + return -1; + } + dir->size = vtfilegetsize(f->source); + vtfileunlock(f->source); + } + filerunlock(f); - return 1; + return 0; +} + +int +vacfiletruncate(VacFile *f, char *uid) +{ + if(vacfileisdir(f)){ + werrstr(ENotFile); + return -1; + } + + if(filelock(f) < 0) + return -1; + + if(f->source->mode != VtORDWR){ + werrstr(EReadOnly); + fileunlock(f); + return -1; + } + if(vtfilelock(f->source, -1) < 0){ + fileunlock(f); + return -1; + } + if(vtfiletruncate(f->source) < 0){ + vtfileunlock(f->source); + fileunlock(f); + return -1; + } + vtfileunlock(f->source); + fileunlock(f); + + filewaccess(f, uid); + + return 0; +} + +int +vacfilesetdir(VacFile *f, VacDir *dir, char *uid) +{ + VacFile *ff; + char *oelem; + u32int mask; + u64int size; + + /* can not set permissions for the root */ + if(vacfileisroot(f)){ + werrstr(ERoot); + return -1; + } + + if(filelock(f) < 0) + return -1; + + if(f->source->mode != VtORDWR){ + werrstr(EReadOnly); + fileunlock(f); + return -1; + } + + filemetalock(f); + + /* check new name does not already exist */ + if(strcmp(f->dir.elem, dir->elem) != 0){ + for(ff = f->up->down; ff; ff=ff->next){ + if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){ + werrstr(EExists); + goto Err; + } + } + + ff = dirlookup(f->up, dir->elem); + if(ff != nil){ + vacfiledecref(ff); + werrstr(EExists); + goto Err; + } + } + + if(vtfilelock2(f->source, f->msource, -1) < 0) + goto Err; + if(!vacfileisdir(f)){ + size = vtfilegetsize(f->source); + if(size != dir->size){ + if(vtfilesetsize(f->source, dir->size) < 0){ + vtfileunlock(f->source); + if(f->msource) + vtfileunlock(f->msource); + goto Err; + } + /* commited to changing it now */ + } + } + /* commited to changing it now */ +#if 0 + if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary)) + filesettmp(f, dir->mode&ModeTemporary); +#endif + vtfileunlock(f->source); + if(f->msource) + vtfileunlock(f->msource); + + oelem = nil; + if(strcmp(f->dir.elem, dir->elem) != 0){ + oelem = f->dir.elem; + f->dir.elem = vtstrdup(dir->elem); + } + + if(strcmp(f->dir.uid, dir->uid) != 0){ + vtfree(f->dir.uid); + f->dir.uid = vtstrdup(dir->uid); + } + + if(strcmp(f->dir.gid, dir->gid) != 0){ + vtfree(f->dir.gid); + f->dir.gid = vtstrdup(dir->gid); + } + + f->dir.mtime = dir->mtime; + f->dir.atime = dir->atime; + +//fprint(2, "mode %x %x ", f->dir.mode, dir->mode); + mask = ~(ModeDir|ModeSnapshot); + f->dir.mode &= ~mask; + f->dir.mode |= mask & dir->mode; + f->dirty = 1; +//fprint(2, "->%x\n", f->dir.mode); + + filemetaflush2(f, oelem); + vtfree(oelem); + + filemetaunlock(f); + fileunlock(f); + + filewaccess(f->up, uid); + + return 0; +Err: + filemetaunlock(f); + fileunlock(f); + return -1; +} + +int +vacfilesetqidspace(VacFile *f, u64int offset, u64int max) +{ + int ret; + + if(filelock(f) < 0) + return -1; + filemetalock(f); + f->dir.qidspace = 1; + f->dir.qidoffset = offset; + f->dir.qidmax = max; + ret = filemetaflush2(f, nil); + filemetaunlock(f); + fileunlock(f); + return ret; } uvlong -vfGetId(VacFile *vf) +vacfilegetid(VacFile *f) { /* immutable */ - return vf->dir.qid; + return f->dir.qid; } ulong -vfGetMcount(VacFile *vf) +vacfilegetmcount(VacFile *f) { ulong mcount; - - vfMetaLock(vf); - mcount = vf->dir.mcount; - vfMetaUnlock(vf); + + filemetalock(f); + mcount = f->dir.mcount; + filemetaunlock(f); return mcount; } +ulong +vacfilegetmode(VacFile *f) +{ + ulong mode; + + filemetalock(f); + mode = f->dir.mode; + filemetaunlock(f); + return mode; +} int -vfIsDir(VacFile *vf) +vacfileisdir(VacFile *f) { /* immutable */ - return (vf->dir.mode & ModeDir) != 0; + return (f->dir.mode & ModeDir) != 0; } int -vfIsRoot(VacFile *vf) +vacfileisroot(VacFile *f) { - return vf == vf->fs->root; + return f == f->fs->root; } int -vfGetSize(VacFile *vf, uvlong *size) +vacfilegetsize(VacFile *f, uvlong *size) { - if(!vfRLock(vf)) + if(filerlock(f) < 0) return 0; - *size = sourceGetSize(vf->source); - vfRUnlock(vf); + if(vtfilelock(f->source, VtOREAD) < 0){ + filerunlock(f); + return -1; + } + *size = vtfilegetsize(f->source); + vtfileunlock(f->source); + filerunlock(f); - return 1; + return 0; +} + +int +vacfilegetvtentry(VacFile *f, VtEntry *e) +{ + if(filerlock(f) < 0) + return 0; + if(vtfilelock(f->source, VtOREAD) < 0){ + filerunlock(f); + return -1; + } + vtfilegetentry(f->source, e); + vtfileunlock(f->source); + filerunlock(f); + + return 0; +} + +void +vacfilemetaflush(VacFile *f, int rec) +{ + VacFile **kids, *p; + int nkids; + int i; + + filemetalock(f); + filemetaflush2(f, nil); + filemetaunlock(f); + + if(!rec || !vacfileisdir(f)) + return; + + if(filelock(f) < 0) + return; + nkids = 0; + for(p=f->down; p; p=p->next) + nkids++; + kids = vtmalloc(nkids*sizeof(VacFile*)); + i = 0; + for(p=f->down; p; p=p->next){ + kids[i++] = p; + p->ref++; + } + fileunlock(f); + + for(i=0; i<nkids; i++){ + vacfilemetaflush(kids[i], 1); + vacfiledecref(kids[i]); + } + vtfree(kids); } +/* assumes metaLock is held */ static int -vfMetaRemove(VacFile *vf, char *user) +filemetaflush2(VacFile *f, char *oelem) { - Lump *u; + VacFile *fp; + VtBlock *b, *bb; MetaBlock mb; - MetaEntry me; - int i; - VacFile *vfp; + MetaEntry me, me2; + int i, n; + u32int boff; - vfp = vf->up; + if(!f->dirty) + return 0; - vfWAccess(vfp, user); + if(oelem == nil) + oelem = f->dir.elem; - vfMetaLock(vf); + fp = f->up; - u = sourceGetLump(vfp->msource, vf->block, 0, 1); - if(u == nil) + if(vtfilelock(fp->msource, -1) < 0) + return 0; + /* can happen if source is clri'ed out from under us */ + if(f->boff == NilBlock) + goto Err1; + b = vtfileblock(fp->msource, f->boff, VtORDWR); + if(b == nil) + goto Err1; + + if(mbunpack(&mb, b->data, fp->msource->dsize) < 0) goto Err; - - if(!mbUnpack(&mb, u->data, u->asize)) + if(mbsearch(&mb, oelem, &i, &me) < 0) goto Err; - if(!mbSearch(&mb, vf->dir.elem, &i, &me) || me.p == nil) + + n = vdsize(&f->dir); +if(0)fprint(2, "old size %d new size %d\n", me.size, n); + + if(mbresize(&mb, &me, n) >= 0){ + /* fits in the block */ + mbdelete(&mb, i, &me); + if(strcmp(f->dir.elem, oelem) != 0) + mbsearch(&mb, f->dir.elem, &i, &me2); + vdpack(&f->dir, &me); + mbinsert(&mb, i, &me); + mbpack(&mb); + vtblockdirty(b); + vtblockput(b); + vtfileunlock(fp->msource); + f->dirty = 0; + return -1; + } + + /* + * moving entry to another block + * it is feasible for the fs to crash leaving two copies + * of the directory entry. This is just too much work to + * fix. Given that entries are only allocated in a block that + * is less than PercentageFull, most modifications of meta data + * will fit within the block. i.e. this code should almost + * never be executed. + */ + boff = filemetaalloc(fp, &f->dir, f->boff+1); + if(boff == NilBlock){ + /* mbResize might have modified block */ + mbpack(&mb); + vtblockdirty(b); 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; + } +fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff); + f->boff = boff; + + /* make sure deletion goes to disk after new entry */ + bb = vtfileblock(fp->msource, f->boff, VtORDWR); + mbdelete(&mb, i, &me); + mbpack(&mb); +// blockDependency(b, bb, -1, nil, nil); + vtblockput(bb); + vtblockdirty(b); + vtblockput(b); + vtfileunlock(fp->msource); + + f->dirty = 0; -Err: - lumpDecRef(u, 1); - vfMetaUnlock(vf); return 0; + +Err: + vtblockput(b); +Err1: + vtfileunlock(fp->msource); + return -1; } +static int +filemetaremove(VacFile *f, char *uid) +{ + VtBlock *b; + MetaBlock mb; + MetaEntry me; + int i; + VacFile *up; + + b = nil; + up = f->up; + filewaccess(up, uid); + filemetalock(f); + + if(vtfilelock(up->msource, VtORDWR) < 0) + goto Err; + b = vtfileblock(up->msource, f->boff, VtORDWR); + if(b == nil) + goto Err; + + if(mbunpack(&mb, b->data, up->msource->dsize) < 0) + goto Err; + if(mbsearch(&mb, f->dir.elem, &i, &me) < 0) + goto Err; + mbdelete(&mb, i, &me); + mbpack(&mb); + vtfileunlock(up->msource); + + vtblockdirty(b); + vtblockput(b); + f->removed = 1; + f->boff = NilBlock; + f->dirty = 0; + + filemetaunlock(f); + return 0; + +Err: + vtfileunlock(up->msource); + vtblockput(b); + filemetaunlock(f); + return -1; +} + +/* assume file is locked, assume f->msource is locked */ static int -vfCheckEmpty(VacFile *vf) +filecheckempty(VacFile *f) { - int i, n; - Lump *u; + u32int i, n; + VtBlock *b; MetaBlock mb; - Source *r; + VtFile *r; - r = vf->msource; - n = sourceGetNumBlocks(r); - for(i=0; i<n; i++) { - u = sourceGetLump(r, i, 1, 1); - if(u == nil) + r = f->msource; + n = (vtfilegetsize(r)+r->dsize-1)/r->dsize; + for(i=0; i<n; i++){ + b = vtfileblock(r, i, VtORDWR); + if(b == nil) goto Err; - if(!mbUnpack(&mb, u->data, u->asize)) + if(mbunpack(&mb, b->data, r->dsize) < 0) goto Err; - if(mb.nindex > 0) { - vtSetError(ENotEmpty); + if(mb.nindex > 0){ + werrstr(ENotEmpty); goto Err; } - lumpDecRef(u, 1); + vtblockput(b); } - return 1; -Err: - lumpDecRef(u, 1); return 0; +Err: + vtblockput(b); + return -1; } int -vfRemove(VacFile *vf, char *user) -{ +vacfileremove(VacFile *f, char *muid) +{ + VacFile *ff; + /* can not remove the root */ - if(vfIsRoot(vf)) { - vtSetError(ERoot); - return 0; + if(vacfileisroot(f)){ + werrstr(ERoot); + return -1; } - if(!vfLock(vf)) - return 0; + if(filelock(f) < 0) + return -1; - if(vfIsDir(vf) && !vfCheckEmpty(vf)) + if(f->source->mode != VtORDWR){ + werrstr(EReadOnly); + goto Err1; + } + if(vtfilelock2(f->source, f->msource, -1) < 0) + goto Err1; + if(vacfileisdir(f) && filecheckempty(f)<0) 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); + + for(ff=f->down; ff; ff=ff->next) + assert(ff->removed); + + vtfileremove(f->source); + f->source = nil; + if(f->msource){ + vtfileremove(f->msource); + f->msource = nil; + } + + fileunlock(f); + + if(filemetaremove(f, muid) < 0) + return -1; + return 0; -} -VacFile * -vfIncRef(VacFile *vf) -{ - vfMetaLock(vf); - assert(vf->ref > 0); - vf->ref++; - vfMetaUnlock(vf); - return vf; +Err: + vtfileunlock(f->source); + if(f->msource) + vtfileunlock(f->msource); +Err1: + fileunlock(f); + return -1; } -void -vfDecRef(VacFile *vf) +static int +clri(VacFile *f, char *uid) { - VacFile *p, *q, **qq; - - if(vf->up == nil) { - vfFree(vf); - return; - } + int r; - vfMetaLock(vf); - vf->ref--; - if(vf->ref > 0) { - vfMetaUnlock(vf); - return; + if(f == nil) + return -1; + if(f->up->source->mode != VtORDWR){ + werrstr(EReadOnly); + vacfiledecref(f); + return -1; } - 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); + r = filemetaremove(f, uid); + vacfiledecref(f); + return r; +} - vfDecRef(p); +int +vacfileclripath(VacFs *fs, char *path, char *uid) +{ + return clri(_fileopen(fs, path, 1), uid); } int -vfGetVtEntry(VacFile *vf, VtEntry *e) +vacfileclri(VacFile *dir, char *elem, char *uid) { - int res; + return clri(_filewalk(dir, elem, 1), uid); +} - if(!vfRLock(vf)) - return 0; - res = sourceGetVtEntry(vf->source, e); - vfRUnlock(vf); - return res; +VacFile* +vacfileincref(VacFile *vf) +{ + filemetalock(vf); + assert(vf->ref > 0); + vf->ref++; + filemetaunlock(vf); + return vf; } int -vfGetBlockScore(VacFile *vf, ulong bn, uchar score[VtScoreSize]) +vacfiledecref(VacFile *f) { - Lump *u; - int ret, off; - Source *r; + VacFile *p, *q, **qq; - if(!vfRLock(vf)) + if(f->up == nil){ + /* never linked in */ + assert(f->ref == 1); + filefree(f); return 0; + } - r = vf->source; - - u = sourceWalk(r, bn, 1, &off); - if(u == nil){ - vfRUnlock(vf); - return 0; + filemetalock(f); + f->ref--; + if(f->ref > 0){ + filemetaunlock(f); + return -1; } + assert(f->ref == 0); + assert(f->down == nil); - ret = lumpGetScore(u, off, score); - lumpDecRef(u, 0); - vfRUnlock(vf); + filemetaflush2(f, nil); - return ret; + p = f->up; + qq = &p->down; + for(q = *qq; q; q = *qq){ + if(q == f) + break; + qq = &q->next; + } + assert(q != nil); + *qq = f->next; + + filemetaunlock(f); + filefree(f); + vacfiledecref(p); + return 0; } -VacFile * -vfGetParent(VacFile *vf) +VacFile* +filegetparent(VacFile *f) { - if(vfIsRoot(vf)) - return vfIncRef(vf); - return vfIncRef(vf->up); + if(vacfileisroot(f)) + return vacfileincref(f); + return vacfileincref(f->up); } -static VacDirEnum * -vdeAlloc(VacFile *vf) +VacDirEnum* +vdeopen(VacFile *f) { - VacDirEnum *ds; + VacDirEnum *vde; + VacFile *p; - if(!(vf->dir.mode & ModeDir)) { - vtSetError(ENotDir); - vfDecRef(vf); + if(!vacfileisdir(f)){ + werrstr(ENotDir); 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) + /* flush out meta data */ + if(filelock(f) < 0) return nil; + for(p=f->down; p; p=p->next) + filemetaflush2(p, nil); + fileunlock(f); - return vdeAlloc(vf); -} + vde = vtmallocz(sizeof(VacDirEnum)); + vde->file = vacfileincref(f); -VacDirEnum * -vfDirEnum(VacFile *vf) -{ - return vdeAlloc(vfIncRef(vf)); + return vde; } static int -dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size) +direntrysize(VtFile *s, ulong elem, ulong gen, uvlong *size) { - Lump *u; + VtBlock *b; ulong bn; VtEntry e; + int epb; - bn = elem/s->epb; - elem -= bn*s->epb; + epb = s->dsize/VtEntrySize; + bn = elem/epb; + elem -= bn*epb; - u = sourceGetLump(s, bn, 1, 1); - if(u == nil) + b = vtfileblock(s, bn, VtOREAD); + if(b == nil) goto Err; - if(u->asize < (elem+1)*VtEntrySize) { - vtSetError(ENoDir); + if(vtentryunpack(&e, b->data, elem) < 0) 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; + /* hanging entries are returned as zero size */ + if(!(e.flags & VtEntryActive) || e.gen != gen) + *size = 0; + else + *size = e.size; + vtblockput(b); + return 0; Err: - lumpDecRef(u, 1); - return 0; + vtblockput(b); + return -1; } -int -vdeRead(VacDirEnum *ds, VacDir *dir, int n) +static int +vdefill(VacDirEnum *vde) { - ulong nb; - int i; - Source *meta, *source; + int i, n; + VtFile *meta, *source; MetaBlock mb; MetaEntry me; - Lump *u; + VacFile *f; + VtBlock *b; + VacDir *de; - vfRAccess(ds->file); + /* clean up first */ + for(i=vde->i; i<vde->n; i++) + vdcleanup(vde->buf+i); + vtfree(vde->buf); + vde->buf = nil; + vde->i = 0; + vde->n = 0; - if(!vfRLock(ds->file)) - return -1; + f = vde->file; - 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) + source = f->source; + meta = f->msource; + + b = vtfileblock(meta, vde->boff, VtOREAD); + if(b == nil) goto Err; - if(!mbUnpack(&mb, u->data, u->asize)) + if(mbunpack(&mb, b->data, meta->dsize) < 0) 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)) + n = mb.nindex; + vde->buf = vtmalloc(n * sizeof(VacDir)); + + for(i=0; i<n; i++){ + de = vde->buf + i; + meunpack(&me, &mb, i); + if(vdunpack(de, &me) < 0) + goto Err; + vde->n++; + if(!(de->mode & ModeDir)) + if(direntrysize(source, de->entry, de->gen, &de->size) < 0) 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; + vde->boff++; + vtblockput(b); + return 0; Err: - lumpDecRef(u, 1); - vfRUnlock(ds->file); - n = i; - for(i=0; i<n ; i++) - vdCleanup(&dir[i]); + vtblockput(b); return -1; } +int +vderead(VacDirEnum *vde, VacDir *de) +{ + int ret, didread; + VacFile *f; + u32int nb; + + f = vde->file; + if(filerlock(f) < 0) + return -1; + + if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){ + filerunlock(f); + return -1; + } + + nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize; + + didread = 0; + while(vde->i >= vde->n){ + if(vde->boff >= nb){ + ret = 0; + goto Return; + } + didread = 1; + if(vdefill(vde) < 0){ + ret = -1; + goto Return; + } + } + + memmove(de, vde->buf + vde->i, sizeof(VacDir)); + vde->i++; + ret = 1; + +Return: + vtfileunlock(f->source); + vtfileunlock(f->msource); + filerunlock(f); + + if(didread) + fileraccess(f); + return ret; +} + void -vdeFree(VacDirEnum *ds) +vdeclose(VacDirEnum *vde) { - if(ds == nil) + int i; + if(vde == nil) return; - vfDecRef(ds->file); - vtMemFree(ds); + for(i=vde->i; i<vde->n; i++) + vdcleanup(vde->buf+i); + vtfree(vde->buf); + vacfiledecref(vde->file); + vtfree(vde); } -static ulong -msAlloc(Source *ms, ulong start, int n) +/* + * caller must lock f->source and f->msource + * caller must NOT lock the source and msource + * referenced by dir. + */ +static u32int +filemetaalloc(VacFile *f, VacDir *dir, u32int start) { - ulong nb, i; - Lump *u; + u32int nb, bo; + VtBlock *b, *bb; MetaBlock mb; + int nn; + uchar *p; + int i, n, epb; + MetaEntry me; + VtFile *s, *ms; + + s = f->source; + ms = f->msource; - nb = sourceGetNumBlocks(ms); - u = nil; + n = vdsize(dir); + nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize; + b = nil; if(start > nb) start = nb; - for(i=start; i<nb; i++) { - u = sourceGetLump(ms, i, 1, 1); - if(u == nil) + for(bo=start; bo<nb; bo++){ + b = vtfileblock(ms, bo, VtORDWR); + if(b == nil) goto Err; - if(!mbUnpack(&mb, u->data, ms->dsize)) + if(mbunpack(&mb, b->data, ms->dsize) < 0) goto Err; - if(mb.maxsize - mb.size + mb.free >= n && mb.nindex < mb.maxindex) + nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free; + if(n <= nn && mb.nindex < mb.maxindex) break; - lumpDecRef(u, 1); - u = nil; + vtblockput(b); + b = 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) + if(b == nil){ + b = vtfileblock(ms, bo, VtORDWR); + if(b == nil) goto Err; - sourceSetSize(ms, (nb+1)*ms->dsize); - mbInit(&mb, u->data, u->asize); - mbPack(&mb); + vtfilesetsize(ms, (nb+1)*ms->dsize); + mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry); + } + + p = mballoc(&mb, n); + if(p == nil){ + /* mbAlloc might have changed block */ + mbpack(&mb); + vtblockdirty(b); + werrstr(EBadMeta); + goto Err; } - lumpDecRef(u, 1); - return i; + + mbsearch(&mb, dir->elem, &i, &me); + assert(me.p == nil); + me.p = p; + me.size = n; + vdpack(dir, &me); + mbinsert(&mb, i, &me); + mbpack(&mb); + +#ifdef notdef /* XXX */ + /* meta block depends on super block for qid ... */ + bb = cacheLocal(b->c, PartSuper, 0, VtOREAD); + blockDependency(b, bb, -1, nil, nil); + vtblockput(bb); + + /* ... and one or two dir entries */ + epb = s->dsize/VtEntrySize; + bb = vtfileblock(s, dir->entry/epb, VtOREAD); + blockDependency(b, bb, -1, nil, nil); + vtblockput(bb); + if(dir->mode & ModeDir){ + bb = sourceBlock(s, dir->mentry/epb, VtOREAD); + blockDependency(b, bb, -1, nil, nil); + vtblockput(bb); + } +#endif + + vtblockdirty(b); + vtblockput(b); + return bo; Err: - lumpDecRef(u, 1); + vtblockput(b); return NilBlock; } +static int +chksource(VacFile *f) +{ + if(f->partial) + return 0; + + if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){ + werrstr(ERemoved); + return -1; + } + return 0; +} + +static int +filerlock(VacFile *f) +{ +// assert(!canwlock(&f->fs->elk)); + rlock(&f->lk); + if(chksource(f) < 0){ + runlock(&f->lk); + return -1; + } + return 0; +} + +static void +filerunlock(VacFile *f) +{ + runlock(&f->lk); +} + +static int +filelock(VacFile *f) +{ +// assert(!canwlock(&f->fs->elk)); + wlock(&f->lk); + if(chksource(f) < 0){ + wunlock(&f->lk); + return -1; + } + return 0; +} + +static void +fileunlock(VacFile *f) +{ + wunlock(&f->lk); +} + +/* + * f->source and f->msource must NOT be locked. + * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2). + * We have to respect that ordering. + */ +static void +filemetalock(VacFile *f) +{ + assert(f->up != nil); +// assert(!canwlock(&f->fs->elk)); + wlock(&f->up->lk); +} + +static void +filemetaunlock(VacFile *f) +{ + wunlock(&f->up->lk); +} + +/* + * f->source and f->msource must NOT be locked. + * see filemetalock. + */ +static void +fileraccess(VacFile* f) +{ + if(f->mode == VtOREAD) + return; + + filemetalock(f); + f->dir.atime = time(0L); + f->dirty = 1; + filemetaunlock(f); +} + +/* + * f->source and f->msource must NOT be locked. + * see filemetalock. + */ +static void +filewaccess(VacFile* f, char *mid) +{ + if(f->mode == VtOREAD) + return; + + filemetalock(f); + f->dir.atime = f->dir.mtime = time(0L); + if(strcmp(f->dir.mid, mid) != 0){ + vtfree(f->dir.mid); + f->dir.mid = vtstrdup(mid); + } + f->dir.mcount++; + f->dirty = 1; + filemetaunlock(f); + +/*RSC: let's try this */ +/*presotto - lets not + if(f->up) + filewaccess(f->up, mid); +*/ +} + +#if 0 +static void +markCopied(Block *b) +{ + VtBlock *lb; + Label l; + + if(globalToLocal(b->score) == NilBlock) + return; + + if(!(b->l.state & BsCopied)){ + /* + * We need to record that there are now pointers in + * b that are not unique to b. We do this by marking + * b as copied. Since we don't return the label block, + * the caller can't get the dependencies right. So we have + * to flush the block ourselves. This is a rare occurrence. + */ + l = b->l; + l.state |= BsCopied; + lb = _blockSetLabel(b, &l); + WriteAgain: + while(!blockWrite(lb)){ + fprint(2, "getEntry: could not write label block\n"); + sleep(10*1000); + } + while(lb->iostate != BioClean && lb->iostate != BioDirty){ + assert(lb->iostate == BioWriting); + vtSleep(lb->ioready); + } + if(lb->iostate == BioDirty) + goto WriteAgain; + vtblockput(lb); + } +} + +static int +getEntry(VtFile *r, Entry *e, int mark) +{ + Block *b; + + if(r == nil){ + memset(&e, 0, sizeof e); + return 1; + } + + b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtOREAD); + if(b == nil) + return 0; + if(!entryUnpack(e, b->data, r->offset % r->epb)){ + vtblockput(b); + return 0; + } + + if(mark) + markCopied(b); + vtblockput(b); + return 1; +} + +static int +setEntry(Source *r, Entry *e) +{ + Block *b; + Entry oe; + + b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtORDWR); + if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score); + if(b == nil) + return 0; + if(!entryUnpack(&oe, b->data, r->offset % r->epb)){ + vtblockput(b); + return 0; + } + e->gen = oe.gen; + entryPack(e, b->data, r->offset % r->epb); + + /* BUG b should depend on the entry pointer */ + + markCopied(b); + vtblockdirty(b); + vtblockput(b); + return 1; +} + +/* assumes hold elk */ +int +fileSnapshot(VacFile *dst, VacFile *src, u32int epoch, int doarchive) +{ + Entry e, ee; + + /* add link to snapshot */ + if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1)) + return 0; + + e.snap = epoch; + e.archive = doarchive; + ee.snap = epoch; + ee.archive = doarchive; + + if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee)) + return 0; + return 1; +} + +int +fileGetSources(VacFile *f, Entry *e, Entry *ee, int mark) +{ + if(!getEntry(f->source, e, mark) + || !getEntry(f->msource, ee, mark)) + return 0; + return 1; +} + +int +fileWalkSources(VacFile *f) +{ + if(f->mode == VtOREAD) + return 1; + if(!sourceLock2(f->source, f->msource, VtORDWR)) + return 0; + vtfileunlock(f->source); + vtfileunlock(f->msource); + return 1; +} + +#endif diff --git a/src/cmd/vac/fns.h b/src/cmd/vac/fns.h index f013f126..335d85c9 100644 --- a/src/cmd/vac/fns.h +++ b/src/cmd/vac/fns.h @@ -1,46 +1,17 @@ -Source *sourceAlloc(Cache*, Lump *u, ulong block, int elem, int readonly); -Source *sourceOpen(Source*, ulong entry, int readOnly); -Source *sourceCreate(Source*, int psize, int dsize, int isdir, ulong entry); -Lump *sourceGetLump(Source*, ulong block, int readOnly, int lock); -Lump *sourceWalk(Source *r, ulong block, int readOnly, int *); -int sourceSetDepth(Source *r, uvlong size); -int sourceSetSize(Source *r, uvlong size); -uvlong sourceGetSize(Source *r); -int sourceSetDirSize(Source *r, ulong size); -ulong sourceGetDirSize(Source *r); -void sourceRemove(Source*); -void sourceFree(Source*); -int sourceGetVtEntry(Source *r, VtEntry *dir); -ulong sourceGetNumBlocks(Source *r); +int mbunpack(MetaBlock *mb, uchar *p, int n); +void mbinsert(MetaBlock *mb, int i, MetaEntry*); +void mbdelete(MetaBlock *mb, int i, MetaEntry*); +void mbpack(MetaBlock *mb); +uchar *mballoc(MetaBlock *mb, int n); -Lump *lumpWalk(Lump *u, int offset, int type, int size, int readOnly, int lock); -int lumpGetScore(Lump *u, int offset, uchar score[VtScoreSize]); -void lumpDecRef(Lump*, int unlock); -Lump *lumpIncRef(Lump*); -void lumpFreeEntry(Lump *u, int entry); +int meunpack(MetaEntry*, MetaBlock *mb, int i); +int mecmp(MetaEntry*, char *s); +int mecmpnew(MetaEntry*, char *s); -Cache *cacheAlloc(VtSession *z, int blockSize, long nblocks); -Lump *cacheAllocLump(Cache *c, int type, int size, int dir); -void cacheFree(Cache *c); -long cacheGetSize(Cache*); -int cacheSetSize(Cache*, long); -int cacheGetBlockSize(Cache *c); -Lump *cacheGetLump(Cache *c, uchar score[VtScoreSize], int type, int size); -void cacheCheck(Cache*); +int vdsize(VacDir *dir); +int vdunpack(VacDir *dir, MetaEntry*); +void vdpack(VacDir *dir, MetaEntry*); -int mbUnpack(MetaBlock *mb, uchar *p, int n); -void mbInsert(MetaBlock *mb, int i, MetaEntry*); -void mbDelete(MetaBlock *mb, int i, MetaEntry*); -void mbPack(MetaBlock *mb); -uchar *mbAlloc(MetaBlock *mb, int n); - -int meUnpack(MetaEntry*, MetaBlock *mb, int i); -int meCmp(MetaEntry*, char *s); -int meCmpNew(MetaEntry*, char *s); - -int vdSize(VacDir *dir); -int vdUnpack(VacDir *dir, MetaEntry*); -void vdPack(VacDir *dir, MetaEntry*); - -VacFile *vfRoot(VacFS *fs, uchar *score); +VacFile *_vacfileroot(VacFs *fs, VtFile *file); +int _vacfsnextqid(VacFs *fs, uvlong *qid); diff --git a/src/cmd/vac/fs.c b/src/cmd/vac/fs.c index 568e2ece..e6902d59 100644 --- a/src/cmd/vac/fs.c +++ b/src/cmd/vac/fs.c @@ -5,100 +5,107 @@ static char EBadVacFormat[] = "bad format for vac file"; -static VacFS * -vfsAlloc(VtSession *z, int bsize, long ncache) +static VacFs * +vacfsalloc(VtConn *z, int bsize, int ncache, int mode) { - VacFS *fs; + VacFs *fs; - fs = vtMemAllocZ(sizeof(VacFS)); + fs = vtmallocz(sizeof(VacFs)); fs->ref = 1; fs->z = z; fs->bsize = bsize; - fs->cache = cacheAlloc(z, bsize, ncache); + fs->cache = vtcachealloc(z, bsize, ncache, mode); return fs; } static int -readScore(int fd, uchar score[VtScoreSize]) +readscore(int fd, uchar score[VtScoreSize]) { - char buf[44]; - int i, n, c; + char buf[45], *pref; + int n; - n = readn(fd, buf, sizeof(buf)); + n = readn(fd, buf, sizeof(buf)-1); if(n < sizeof(buf)) { - vtSetError("short read"); - return 0; + werrstr("short read"); + return -1; } - if(strncmp(buf, "vac:", 4) != 0) { - vtSetError("not a vac file"); - return 0; + buf[n] = 0; + + if(vtparsescore(buf, &pref, score) < 0){ + werrstr(EBadVacFormat); + return -1; } - memset(score, 0, VtScoreSize); - for(i=4; i<sizeof(buf); i++) { - if(buf[i] >= '0' && buf[i] <= '9') - c = buf[i] - '0'; - else if(buf[i] >= 'a' && buf[i] <= 'f') - c = buf[i] - 'a' + 10; - else if(buf[i] >= 'A' && buf[i] <= 'F') - c = buf[i] - 'A' + 10; - else { - vtSetError("bad format for venti score"); - return 0; - } - if((i & 1) == 0) - c <<= 4; - - score[(i>>1)-2] |= c; + if(pref==nil || strcmp(pref, "vac") != 0) { + werrstr("not a vac file"); + return -1; } - return 1; + return 0; } -VacFS * -vfsOpen(VtSession *z, char *file, int readOnly, long ncache) +VacFs* +vacfsopen(VtConn *z, char *file, int mode, int ncache) { - VacFS *fs; - int n, fd; - VtRoot rt; - uchar score[VtScoreSize], buf[VtRootSize]; - VacFile *root; + int fd; + uchar score[VtScoreSize]; fd = open(file, OREAD); - if(fd < 0) { - vtOSError(); + if(fd < 0) return nil; - } - if(!readScore(fd, score)) { + if(readscore(fd, score) < 0){ close(fd); return nil; } close(fd); - n = vtRead(z, score, VtRootType, buf, VtRootSize); + return vacfsopenscore(z, score, mode, ncache); +} + +VacFs* +vacfsopenscore(VtConn *z, u8int *score, int mode, int ncache) +{ + VacFs *fs; + int n; + VtRoot rt; + uchar buf[VtRootSize]; + VacFile *root; + VtFile *r; + VtEntry e; + + n = vtread(z, score, VtRootType, buf, VtRootSize); if(n < 0) return nil; - if(n != VtRootSize) { - vtSetError("vtRead on root too short"); - return nil; - } - - if(!vtSha1Check(score, buf, VtRootSize)) { - vtSetError("vtSha1Check failed on root block"); + if(n != VtRootSize){ + werrstr("vtread on root too short"); return nil; } - if(!vtRootUnpack(&rt, buf)) + if(vtrootunpack(&rt, buf) < 0) return nil; if(strcmp(rt.type, "vac") != 0) { - vtSetError("not a vac root"); + werrstr("not a vac root"); return nil; } - fs = vfsAlloc(z, rt.blockSize, ncache); + fs = vacfsalloc(z, rt.blocksize, ncache, mode); memmove(fs->score, score, VtScoreSize); - fs->readOnly = readOnly; - root = vfRoot(fs, rt.score); + fs->mode = mode; + + memmove(e.score, score, VtScoreSize); + e.gen = 0; + e.psize = (rt.blocksize/VtEntrySize)*VtEntrySize; + e.dsize = rt.blocksize; + e.type = VtDirType; + e.flags = VtEntryActive; + e.size = 3*VtEntrySize; + + root = nil; + if((r = vtfileopenroot(fs->cache, &e)) == nil) + goto Err; + + root = _vacfileroot(fs, r); + vtfileclose(r); if(root == nil) goto Err; fs->root = root; @@ -106,83 +113,63 @@ vfsOpen(VtSession *z, char *file, int readOnly, long ncache) return fs; Err: if(root) - vfDecRef(root); - vfsClose(fs); + vacfiledecref(root); + vacfsclose(fs); return nil; } -VacFS * -vacFsCreate(VtSession *z, int bsize, long ncache) +VacFs * +vacfscreate(VtConn *z, int bsize, int ncache) { - VacFS *fs; - - fs = vfsAlloc(z, bsize, ncache); - return fs; + return vacfsalloc(z, bsize, ncache, VtORDWR); } int -vfsIsReadOnly(VacFS *fs) +vacfsmode(VacFs *fs) { - return fs->readOnly != 0; + return fs->mode; } -VacFile * -vfsGetRoot(VacFS *fs) +VacFile* +vacfsgetroot(VacFs *fs) { - return vfIncRef(fs->root); + return vacfileincref(fs->root); } int -vfsGetBlockSize(VacFS *fs) +vacfsgetblocksize(VacFs *fs) { return fs->bsize; } int -vfsGetScore(VacFS *fs, uchar score[VtScoreSize]) -{ - memmove(fs, score, VtScoreSize); - return 1; -} - -long -vfsGetCacheSize(VacFS *fs) +vacfsgetscore(VacFs *fs, u8int *score) { - return cacheGetSize(fs->cache); + memmove(score, fs->score, VtScoreSize); + return 0; } int -vfsSetCacheSize(VacFS *fs, long size) +_vacfsnextqid(VacFs *fs, uvlong *qid) { - return cacheSetSize(fs->cache, size); + ++fs->qid; + *qid = fs->qid; + return 0; } int -vfsSnapshot(VacFS *fs, char *src, char *dst) +vacfssync(VacFs *fs) { - USED(fs); - USED(src); - USED(dst); - return 1; + return 0; } -int -vfsSync(VacFS*) -{ - return 1; -} - -int -vfsClose(VacFS *fs) +void +vacfsclose(VacFs *fs) { if(fs->root) - vfDecRef(fs->root); + vacfiledecref(fs->root); fs->root = nil; - cacheCheck(fs->cache); - cacheFree(fs->cache); - memset(fs, 0, sizeof(VacFS)); - vtMemFree(fs); - return 1; + vtcachefree(fs->cache); + vtfree(fs); } - diff --git a/src/cmd/vac/mkfile b/src/cmd/vac/mkfile index ac33ab32..a4b7a298 100644 --- a/src/cmd/vac/mkfile +++ b/src/cmd/vac/mkfile @@ -2,13 +2,12 @@ PLAN9=../../.. <$PLAN9/src/mkhdr LIBFILES=\ - cache\ error\ file\ fs\ - source\ pack\ +SHORTLIB=venti sec thread mux bio 9 LIB=${LIBFILES:%=%.$O} HFILES=\ diff --git a/src/cmd/vac/pack.c b/src/cmd/vac/pack.c index b16834d9..074152ea 100644 --- a/src/cmd/vac/pack.c +++ b/src/cmd/vac/pack.c @@ -12,7 +12,7 @@ struct MetaChunk { ushort index; }; -static int stringUnpack(char **s, uchar **p, int *n); +static int stringunpack(char **s, uchar **p, int *n); /* * integer conversion routines @@ -23,35 +23,35 @@ static int stringUnpack(char **s, uchar **p, int *n); #define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2)) #define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4)) -#define U8PUT(p,v) (p)[0]=(v) -#define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v) -#define U32PUT(p,v) (p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v) +#define U8PUT(p,v) (p)[0]=(v)&0xFF +#define U16PUT(p,v) (p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF +#define U32PUT(p,v) (p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF #define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32) #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32) static int -stringUnpack(char **s, uchar **p, int *n) +stringunpack(char **s, uchar **p, int *n) { int nn; if(*n < 2) - return 0; + return -1; nn = U16GET(*p); *p += 2; *n -= 2; if(nn > *n) - return 0; - *s = vtMemAlloc(nn+1); + return -1; + *s = vtmalloc(nn+1); memmove(*s, *p, nn); (*s)[nn] = 0; *p += nn; *n -= nn; - return 1; + return 0; } static int -stringPack(char *s, uchar *p) +stringpack(char *s, uchar *p) { int n; @@ -63,7 +63,7 @@ stringPack(char *s, uchar *p) int -mbUnpack(MetaBlock *mb, uchar *p, int n) +mbunpack(MetaBlock *mb, uchar *p, int n) { u32int magic; @@ -72,13 +72,13 @@ mbUnpack(MetaBlock *mb, uchar *p, int n) if(n == 0) { memset(mb, 0, sizeof(MetaBlock)); - return 1; + return 0; } magic = U32GET(p); if(magic != MetaMagic && magic != MetaMagic+1) { - vtSetError("bad meta block magic"); - return 0; + werrstr("bad meta block magic"); + return -1; } mb->size = U16GET(p+4); mb->free = U16GET(p+6); @@ -87,22 +87,22 @@ mbUnpack(MetaBlock *mb, uchar *p, int n) mb->unbotch = (magic == MetaMagic+1); if(mb->size > n) { - vtSetError("bad meta block size"); - return 0; + werrstr("bad meta block size"); + return -1; } p += MetaHeaderSize; n -= MetaHeaderSize; USED(p); if(n < mb->maxindex*MetaIndexSize) { - vtSetError("truncated meta block 2"); - return 0; + werrstr("truncated meta block 2"); + return -1; } - return 1; + return 0; } void -mbPack(MetaBlock *mb) +mbpack(MetaBlock *mb) { uchar *p; @@ -117,7 +117,7 @@ mbPack(MetaBlock *mb) void -mbDelete(MetaBlock *mb, int i, MetaEntry *me) +mbdelete(MetaBlock *mb, int i, MetaEntry *me) { uchar *p; int n; @@ -137,7 +137,7 @@ mbDelete(MetaBlock *mb, int i, MetaEntry *me) } void -mbInsert(MetaBlock *mb, int i, MetaEntry *me) +mbinsert(MetaBlock *mb, int i, MetaEntry *me) { uchar *p; int o, n; @@ -161,14 +161,14 @@ mbInsert(MetaBlock *mb, int i, MetaEntry *me) } int -meUnpack(MetaEntry *me, MetaBlock *mb, int i) +meunpack(MetaEntry *me, MetaBlock *mb, int i) { uchar *p; int eo, en; if(i < 0 || i >= mb->nindex) { - vtSetError("bad meta entry index"); - return 0; + werrstr("bad meta entry index"); + return -1; } p = mb->buf + MetaHeaderSize + i*MetaIndexSize; @@ -177,32 +177,32 @@ meUnpack(MetaEntry *me, MetaBlock *mb, int i) if(0)print("eo = %d en = %d\n", eo, en); if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) { - vtSetError("corrupted entry in meta block"); - return 0; + werrstr("corrupted entry in meta block"); + return -1; } if(eo+en > mb->size) { - vtSetError("truncated meta block"); - return 0; + werrstr("truncated meta block"); + return -1; } p = mb->buf + eo; /* make sure entry looks ok and includes an elem name */ if(en < 8 || U32GET(p) != DirMagic || en < 8 + U16GET(p+6)) { - vtSetError("corrupted meta block entry"); - return 0; + werrstr("corrupted meta block entry"); + return -1; } me->p = p; me->size = en; - return 1; + return 0; } /* assumes a small amount of checking has been done in mbEntry */ int -meCmp(MetaEntry *me, char *s) +mecmp(MetaEntry *me, char *s) { int n; uchar *p; @@ -230,7 +230,7 @@ meCmp(MetaEntry *me, char *s) } int -meCmpNew(MetaEntry *me, char *s) +mecmpnew(MetaEntry *me, char *s) { int n; uchar *p; @@ -258,9 +258,9 @@ meCmpNew(MetaEntry *me, char *s) } static int -offsetCmp(void *s0, void *s1) +offsetcmp(const void *s0, const void *s1) { - MetaChunk *mc0, *mc1; + const MetaChunk *mc0, *mc1; mc0 = s0; mc1 = s1; @@ -272,13 +272,13 @@ offsetCmp(void *s0, void *s1) } static MetaChunk * -metaChunks(MetaBlock *mb) +metachunks(MetaBlock *mb) { MetaChunk *mc; int oo, o, n, i; uchar *p; - mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk)); + mc = vtmalloc(mb->nindex*sizeof(MetaChunk)); p = mb->buf + MetaHeaderSize; for(i = 0; i<mb->nindex; i++) { mc[i].offset = U16GET(p); @@ -287,7 +287,7 @@ metaChunks(MetaBlock *mb) p += MetaIndexSize; } - qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp); + qsort(mc, mb->nindex, sizeof(MetaChunk), offsetcmp); /* check block looks ok */ oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; @@ -307,12 +307,12 @@ metaChunks(MetaBlock *mb) return mc; Err: - vtMemFree(mc); + vtfree(mc); return nil; } static void -mbCompact(MetaBlock *mb, MetaChunk *mc) +mbcompact(MetaBlock *mb, MetaChunk *mc) { int oo, o, n, i; @@ -333,7 +333,7 @@ mbCompact(MetaBlock *mb, MetaChunk *mc) } uchar * -mbAlloc(MetaBlock *mb, int n) +mballoc(MetaBlock *mb, int n) { int i, o; MetaChunk *mc; @@ -346,33 +346,33 @@ mbAlloc(MetaBlock *mb, int n) if(mb->maxsize - mb->size + mb->free < n) return nil; - mc = metaChunks(mb); + mc = metachunks(mb); /* look for hole */ o = MetaHeaderSize + mb->maxindex*MetaIndexSize; for(i=0; i<mb->nindex; i++) { if(mc[i].offset - o >= n) { - vtMemFree(mc); + vtfree(mc); return mb->buf + o; } o = mc[i].offset + mc[i].size; } if(mb->maxsize - o >= n) { - vtMemFree(mc); + vtfree(mc); return mb->buf + o; } /* compact and return off the end */ - mbCompact(mb, mc); - vtMemFree(mc); + mbcompact(mb, mc); + vtfree(mc); assert(mb->maxsize - mb->size >= n); return mb->buf + mb->size; } int -vdSize(VacDir *dir) +vdsize(VacDir *dir) { int n; @@ -399,17 +399,17 @@ vdSize(VacDir *dir) n += 2 + strlen(dir->mid); /* optional sections */ - if(dir->qidSpace) { + if(dir->qidspace) { n += 3 + /* option header */ - 8 + /* qidOffset */ - 8; /* qid Max */ + 8 + /* qid offset */ + 8; /* qid max */ } return n; } void -vdPack(VacDir *dir, MetaEntry *me) +vdpack(VacDir *dir, MetaEntry *me) { uchar *p; ulong t32; @@ -420,7 +420,7 @@ vdPack(VacDir *dir, MetaEntry *me) U16PUT(p+4, 9); /* version */ p += 6; - p += stringPack(dir->elem, p); + p += stringpack(dir->elem, p); U32PUT(p, dir->entry); U32PUT(p+4, dir->gen); @@ -429,9 +429,9 @@ vdPack(VacDir *dir, MetaEntry *me) U64PUT(p+16, dir->qid, t32); p += 24; - p += stringPack(dir->uid, p); - p += stringPack(dir->gid, p); - p += stringPack(dir->mid, p); + p += stringpack(dir->uid, p); + p += stringpack(dir->gid, p); + p += stringpack(dir->mid, p); U32PUT(p, dir->mtime); U32PUT(p+4, dir->mcount); @@ -440,12 +440,12 @@ vdPack(VacDir *dir, MetaEntry *me) U32PUT(p+16, dir->mode); p += 5*4; - if(dir->qidSpace) { + if(dir->qidspace) { U8PUT(p, DirQidSpaceEntry); U16PUT(p+1, 2*8); p += 3; - U64PUT(p, dir->qidOffset, t32); - U64PUT(p+8, dir->qidMax, t32); + U64PUT(p, dir->qidoffset, t32); + U64PUT(p+8, dir->qidmax, t32); } assert(p == me->p + me->size); @@ -453,7 +453,7 @@ vdPack(VacDir *dir, MetaEntry *me) int -vdUnpack(VacDir *dir, MetaEntry *me) +vdunpack(VacDir *dir, MetaEntry *me) { int t, nn, n, version; uchar *p; @@ -483,7 +483,7 @@ if(0)print("vdUnpack: got magic\n"); if(0)print("vdUnpack: got version\n"); /* elem */ - if(!stringUnpack(&dir->elem, &p, &n)) + if(stringunpack(&dir->elem, &p, &n) < 0) goto Err; if(0)print("vdUnpack: got elem\n"); @@ -532,15 +532,15 @@ if(0)print("vdUnpack: got qid\n"); } /* uid */ - if(!stringUnpack(&dir->uid, &p, &n)) + if(stringunpack(&dir->uid, &p, &n) < 0) goto Err; /* gid */ - if(!stringUnpack(&dir->gid, &p, &n)) + if(stringunpack(&dir->gid, &p, &n) < 0) goto Err; /* mid */ - if(!stringUnpack(&dir->mid, &p, &n)) + if(stringunpack(&dir->mid, &p, &n) < 0) goto Err; if(0)print("vdUnpack: got ids\n"); @@ -584,11 +584,11 @@ if(0)print("vdUnpack: got times\n"); break; break; case DirQidSpaceEntry: - if(dir->qidSpace || nn != 16) + if(dir->qidspace || nn != 16) goto Err; - dir->qidSpace = 1; - dir->qidOffset = U64GET(p); - dir->qidMax = U64GET(p+8); + dir->qidspace = 1; + dir->qidoffset = U64GET(p); + dir->qidmax = U64GET(p+8); break; } p += nn; @@ -600,10 +600,112 @@ if(0)print("vdUnpack: got options\n"); goto Err; if(0)print("vdUnpack: correct size\n"); - return 1; + return 0; Err: if(0)print("vdUnpack: XXXXXXXXXXXX EbadMeta\n"); - vtSetError(EBadMeta); - vdCleanup(dir); - return 0; + werrstr(EBadMeta); + vdcleanup(dir); + return -1; +} + +void +vdcleanup(VacDir *dir) +{ + vtfree(dir->elem); + dir->elem = nil; + vtfree(dir->uid); + dir->uid = nil; + vtfree(dir->gid); + dir->gid = nil; + vtfree(dir->mid); + dir->mid = nil; +} + +void +vdcopy(VacDir *dst, VacDir *src) +{ + *dst = *src; + dst->elem = vtstrdup(dst->elem); + dst->uid = vtstrdup(dst->uid); + dst->gid = vtstrdup(dst->gid); + dst->mid = vtstrdup(dst->mid); +} + +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) < 0) + 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; +} + +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; +} + +int +mbresize(MetaBlock *mb, MetaEntry *me, int n) +{ + uchar *p, *ep; + + /* easy case */ + if(n <= me->size){ + me->size = n; + return 0; + } + + /* try and expand entry */ + + p = me->p + me->size; + ep = mb->buf + mb->maxsize; + while(p < ep && *p == 0) + p++; + if(n <= p - me->p){ + me->size = n; + return 0; + } + + p = mballoc(mb, n); + if(p != nil){ + me->p = p; + me->size = n; + return 0; + } + + return -1; } diff --git a/src/cmd/vac/source.c b/src/cmd/vac/source.c deleted file mode 100644 index e7245a2f..00000000 --- a/src/cmd/vac/source.c +++ /dev/null @@ -1,390 +0,0 @@ -#include "stdinc.h" -#include "vac.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -static int sizeToDepth(uvlong s, int psize, int dsize); - -static int -sizeToDepth(uvlong s, int psize, int dsize) -{ - int np; - int d; - - /* determine pointer depth */ - np = psize/VtScoreSize; - s = (s + dsize - 1)/dsize; - for(d = 0; s > 1; d++) - s = (s + np - 1)/np; - return d; -} - -/* assumes u is lock? */ -Source * -sourceAlloc(Cache *c, Lump *u, ulong block, int entry, int readOnly) -{ - Source *r; - VtEntry d; - - if(u->asize < (entry+1)*VtEntrySize) { - vtSetError(ENoDir); - return nil; - } - - if(!vtEntryUnpack(&d, u->data, entry)) - return nil; - - if(!(d.flags & VtEntryActive)) { -fprint(2, "bad flags %#ux %V\n", d.flags, d.score); - vtSetError(ENoDir); - return nil; - } - - /* HACK for backwards compatiblity - should go away at some point */ - if(d.depth == 0) { -if(d.size > d.dsize) fprint(2, "depth == 0! size = %ulld\n", d.size); - d.depth = sizeToDepth(d.size, d.psize, d.dsize); - } - - if(d.depth < sizeToDepth(d.size, d.psize, d.dsize)) { - vtSetError(EBadDir); - return nil; - } - - r = vtMemAllocZ(sizeof(Source)); - r->lk = vtLockAlloc(); - r->cache = c; - r->readOnly = readOnly; - r->lump = lumpIncRef(u); - r->block = block; - r->entry = entry; - r->gen = d.gen; - r->dir = (d.flags & VtEntryDir) != 0; - r->depth = d.depth; - r->psize = d.psize; - r->dsize = d.dsize; - r->size = d.size; - - r->epb = r->dsize/VtEntrySize; - - return r; -} - -Source * -sourceOpen(Source *r, ulong entry, int readOnly) -{ - ulong bn; - Lump *u; - -if(0)fprint(2, "sourceOpen: %V:%d: %lud\n", r->lump->score, r->entry, entry); - if(r->readOnly && !readOnly) { - vtSetError(EReadOnly); - return nil; - } - - bn = entry/r->epb; - - u = sourceGetLump(r, bn, readOnly, 1); - if(u == nil) - return nil; - - r = sourceAlloc(r->cache, u, bn, entry%r->epb, readOnly); - lumpDecRef(u, 1); - return r; -} - -Source * -sourceCreate(Source *r, int psize, int dsize, int isdir, ulong entry) -{ - Source *rr; - int i; - Lump *u; - ulong bn; - VtEntry dir; - - if(r->readOnly) { - vtSetError(EReadOnly); - return nil; - } - - if(entry == 0) { - /* - * look at a random block to see if we can find an empty entry - */ - entry = sourceGetDirSize(r); - entry = r->epb*lnrand(entry/r->epb+1); - } - - /* - * need to loop since multiple threads could be trying to allocate - */ - for(;;) { - bn = entry/r->epb; - sourceSetDepth(r, (uvlong)(bn+1)*r->dsize); - u = sourceGetLump(r, bn, 0, 1); - if(u == nil) - return nil; - for(i=entry%r->epb; i<r->epb; i++) { - vtEntryUnpack(&dir, u->data, i); - if((dir.flags&VtEntryActive) == 0 && dir.gen != ~0) - goto Found; - } - lumpDecRef(u, 1); - entry = sourceGetDirSize(r); - } -Found: - /* found an entry */ - dir.psize = psize; - dir.dsize = dsize; - dir.flags = VtEntryActive; - if(isdir) - dir.flags |= VtEntryDir; - dir.depth = 0; - dir.size = 0; - memmove(dir.score, vtZeroScore, VtScoreSize); - vtEntryPack(&dir, u->data, i); - - sourceSetDirSize(r, bn*r->epb + i + 1); - rr = sourceAlloc(r->cache, u, bn, i, 0); - - lumpDecRef(u, 1); - return rr; -} - -void -sourceRemove(Source *r) -{ - lumpFreeEntry(r->lump, r->entry); - sourceFree(r); -} - -int -sourceSetDepth(Source *r, uvlong size) -{ - Lump *u, *v; - VtEntry dir; - int depth; - - if(r->readOnly){ - vtSetError(EReadOnly); - return 0; - } - - depth = sizeToDepth(size, r->psize, r->dsize); - - assert(depth >= 0); - - if(depth > VtPointerDepth) { - vtSetError(ETooBig); - return 0; - } - - vtLock(r->lk); - - if(r->depth >= depth) { - vtUnlock(r->lk); - return 1; - } - - u = r->lump; - vtLock(u->lk); - if(!vtEntryUnpack(&dir, u->data, r->entry)) { - vtUnlock(u->lk); - vtUnlock(r->lk); - return 0; - } - while(dir.depth < depth) { - v = cacheAllocLump(r->cache, VtPointerType0+r->depth, r->psize, r->dir); - if(v == nil) - break; - memmove(v->data, dir.score, VtScoreSize); - memmove(dir.score, v->score, VtScoreSize); - dir.depth++; - vtUnlock(v->lk); - } - vtEntryPack(&dir, u->data, r->entry); - vtUnlock(u->lk); - - r->depth = dir.depth; - vtUnlock(r->lk); - - return dir.depth == depth; -} - -int -sourceGetVtEntry(Source *r, VtEntry *dir) -{ - Lump *u; - - u = r->lump; - vtLock(u->lk); - if(!vtEntryUnpack(dir, u->data, r->entry)) { - vtUnlock(u->lk); - return 0; - } - vtUnlock(u->lk); - return 1; -} - -uvlong -sourceGetSize(Source *r) -{ - uvlong size; - - vtLock(r->lk); - size = r->size; - vtUnlock(r->lk); - - return size; -} - - -int -sourceSetSize(Source *r, uvlong size) -{ - Lump *u; - VtEntry dir; - int depth; - - if(r->readOnly) { - vtSetError(EReadOnly); - return 0; - } - - if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize) { - vtSetError(ETooBig); - return 0; - } - - vtLock(r->lk); - depth = sizeToDepth(size, r->psize, r->dsize); - if(size < r->size) { - vtUnlock(r->lk); - return 1; - } - if(depth > r->depth) { - vtSetError(EBadDir); - vtUnlock(r->lk); - return 0; - } - - u = r->lump; - vtLock(u->lk); - vtEntryUnpack(&dir, u->data, r->entry); - dir.size = size; - vtEntryPack(&dir, u->data, r->entry); - vtUnlock(u->lk); - r->size = size; - vtUnlock(r->lk); - return 1; -} - -int -sourceSetDirSize(Source *r, ulong ds) -{ - uvlong size; - - size = (uvlong)r->dsize*(ds/r->epb); - size += VtEntrySize*(ds%r->epb); - return sourceSetSize(r, size); -} - -ulong -sourceGetDirSize(Source *r) -{ - ulong ds; - uvlong size; - - size = sourceGetSize(r); - ds = r->epb*(size/r->dsize); - ds += (size%r->dsize)/VtEntrySize; - return ds; -} - -ulong -sourceGetNumBlocks(Source *r) -{ - return (sourceGetSize(r)+r->dsize-1)/r->dsize; -} - -Lump * -sourceWalk(Source *r, ulong block, int readOnly, int *off) -{ - int depth; - int i, np; - Lump *u, *v; - int elem[VtPointerDepth+1]; - ulong b; - - if(r->readOnly && !readOnly) { - vtSetError(EReadOnly); - return nil; - } - - vtLock(r->lk); - np = r->psize/VtScoreSize; - b = block; - for(i=0; i<r->depth; i++) { - elem[i] = b % np; - b /= np; - } - if(b != 0) { - vtUnlock(r->lk); - vtSetError(EBadOffset); - return nil; - } - elem[i] = r->entry; - u = lumpIncRef(r->lump); - depth = r->depth; - *off = elem[0]; - vtUnlock(r->lk); - - for(i=depth; i>0; i--) { - v = lumpWalk(u, elem[i], VtPointerType0+i-1, r->psize, readOnly, 0); - lumpDecRef(u, 0); - if(v == nil) - return nil; - u = v; - } - - return u; -} - -Lump * -sourceGetLump(Source *r, ulong block, int readOnly, int lock) -{ - int type, off; - Lump *u, *v; - - if(r->readOnly && !readOnly) { - vtSetError(EReadOnly); - return nil; - } - if(block == NilBlock) { - vtSetError(ENilBlock); - return nil; - } -if(0)fprint(2, "sourceGetLump: %V:%d %lud\n", r->lump->score, r->entry, block); - u = sourceWalk(r, block, readOnly, &off); - if(u == nil) - return nil; - if(r->dir) - type = VtDirType; - else - type = VtDataType; - v = lumpWalk(u, off, type, r->dsize, readOnly, lock); - lumpDecRef(u, 0); - return v; -} - -void -sourceFree(Source *k) -{ - if(k == nil) - return; - lumpDecRef(k->lump, 0); - vtLockFree(k->lk); - memset(k, ~0, sizeof(*k)); - vtMemFree(k); -} diff --git a/src/cmd/vac/stdinc.h b/src/cmd/vac/stdinc.h index aca405fc..bf72d3fd 100644 --- a/src/cmd/vac/stdinc.h +++ b/src/cmd/vac/stdinc.h @@ -1,8 +1,5 @@ #include <u.h> #include <libc.h> - -#include "venti.h" - -typedef uvlong u64int; -typedef uchar u8int; -typedef ushort u16int; +#include <thread.h> +#include <venti.h> +#include <libsec.h> diff --git a/src/cmd/vac/vac.c b/src/cmd/vac/vac.c index 8153c37b..f6efb917 100644 --- a/src/cmd/vac/vac.c +++ b/src/cmd/vac/vac.c @@ -1,30 +1,174 @@ -#include <u.h> -#include <libc.h> -#include <venti.h> +#include "stdinc.h" +#include "vac.h" +#include "dat.h" +#include "fns.h" -int bsize; -char *host; -VtConn *z; +typedef struct Sink Sink; +typedef struct MetaSink MetaSink; +typedef struct DirSink DirSink; -void +struct Sink { + VtConn *z; + VtEntry dir; + uchar *buf; + uchar *pbuf[VtPointerDepth+1]; +}; + +struct DirSink { + Sink *sink; + MetaSink *msink; + ulong nentry; + uchar *buf; + uchar *p; /* current pointer */ + uchar *ep; /* end pointer */ +}; + +struct MetaSink { + Sink *sink; + uchar *buf; + int maxindex; + int nindex; + uchar *rp; /* start of current record */ + uchar *p; /* current pointer */ + uchar *ep; /* end pointer */ +}; + +static void usage(void); +static int strpcmp(const void*, const void*); +static void warn(char *fmt, ...); +static void cleanup(void); +static u64int unittoull(char *s); +static void vac(VtConn *z, char *argv[]); +static void vacfile(DirSink *dsink, char *lname, char *sname, VacFile*); +static void vacstdin(DirSink *dsink, char *name, VacFile *vf); +static void vacdata(DirSink *dsink, int fd, char *lname, VacFile*, Dir*); +static void vacdir(DirSink *dsink, int fd, char *lname, char *sname, VacFile*); +static int vacmerge(DirSink *dsink, char *lname, char *sname); + +Sink *sinkalloc(VtConn *z, int psize, int dsize); +void sinkwrite(Sink *k, uchar *data, int n); +void sinkwritescore(Sink *k, uchar *score, int n); +void sinkclose(Sink *k); +void sinkfree(Sink *k); + +DirSink *dirsinkalloc(VtConn *z, int psize, int dsize); +void dirsinkwrite(DirSink *k, VtEntry*); +void dirsinkwritesink(DirSink *k, Sink*); +int dirsinkwritefile(DirSink *k, VacFile *vf); +void dirsinkclose(DirSink *k); +void dirsinkfree(DirSink *k); + +MetaSink *metasinkalloc(VtConn *z, int psize, int dsize); +void metasinkputc(MetaSink *k, int c); +void metasinkputstring(MetaSink *k, char *s); +void metasinkputuint32(MetaSink *k, ulong x); +void metasinkputuint64(MetaSink *k, uvlong x); +void metasinkwrite(MetaSink *k, uchar *data, int n); +void metasinkwritedir(MetaSink *ms, VacDir *vd); +void metasinkeor(MetaSink *k); +void metasinkclose(MetaSink *k); +void metasinkfree(MetaSink *k); +void plan9tovacdir(VacDir*, Dir*, ulong entry, uvlong qid); + +enum { + Version = 8, + BlockSize = 8*1024, + MaxExclude = 1000, +}; + +struct { + ulong file; + ulong sfile; + ulong data; + ulong sdata; + ulong skip; + ulong meta; +} stats; + +int bsize = BlockSize; +int maxbsize; +char *oname, *dfile; +int verbose; +uvlong fileid = 1; +int qdiff; +char *exclude[MaxExclude]; +int nexclude; +int nowrite; +int merge; +char *isi; + +static void usage(void) { - fprint(2, "usage: vac [-b blocksize] [-h host] file\n"); + fprint(2, "usage: %s [-amqsv] [-h host] [-d vacfile] [-b blocksize] [-i name] [-e exclude] [-f vacfile] file ... \n", argv0); + exits("usage"); } void -main(int argc, char *argv[]) +threadmain(int argc, char *argv[]) { + VtConn *z; + char *p; + char *host = nil; + int statsflag = 0; + + atexit(cleanup); + ARGBEGIN{ default: usage(); case 'b': - bsize = unittoull(EARGF(usage())); + p = ARGF(); + if(p == 0) + usage(); + bsize = unittoull(p); + if(bsize == ~0) + usage(); + break; + case 'd': + dfile = ARGF(); + if(dfile == nil) + usage(); + break; + case 'e': + if(nexclude >= MaxExclude) + sysfatal("too many exclusions\n"); + exclude[nexclude] = ARGF(); + if(exclude[nexclude] == nil) + usage(); + nexclude++; + break; + case 'f': + oname = ARGF(); + if(oname == 0) + usage(); break; case 'h': - host = EARGF(usage()); + host = ARGF(); + if(host == nil) + usage(); + break; + case 'i': + isi = ARGF(); + if(isi == nil) + usage(); + break; + case 'n': + nowrite++; + break; + case 'm': + merge++; + break; + case 'q': + qdiff++; break; - }ARGEND + case 's': + statsflag++; + break; + case 'v': + verbose++; + break; + }ARGEND; if(bsize < 512) bsize = 512; @@ -32,45 +176,73 @@ main(int argc, char *argv[]) bsize = VtMaxLumpSize; maxbsize = bsize; - vtAttach(); + fmtinstall('V', vtscorefmt); - fmtinstall('V', vtScoreFmt); - fmtinstall('R', vtErrFmt); - - z = vtDial(host, 0); + z = vtdial(host); if(z == nil) - vtFatal("could not connect to server: %R"); + sysfatal("could not connect to server: %r"); - if(!vtConnect(z, 0)) - vtFatal("vtConnect: %R"); + if(vtconnect(z) < 0) + sysfatal("vtconnect: %r"); - qsort(exclude, nexclude, sizeof(char*), strpCmp); + qsort(exclude, nexclude, sizeof(char*), strpcmp); vac(z, argv); - if(!vtSync(z)) + + if(vtsync(z) < 0) fprint(2, "warning: could not ask server to flush pending writes: %R\n"); - if(statsFlag) + if(statsflag) fprint(2, "files %ld:%ld data %ld:%ld:%ld meta %ld\n", stats.file, stats.sfile, stats.data, stats.skip, stats.sdata, stats.meta); //packetStats(); - vtClose(z); - vtDetach(); + vthangup(z); - exits(0); + threadexitsall(0); } static int -vac(VtSession *z, char *argv[]) +strpcmp(const void *p0, const void *p1) +{ + return strcmp(*(char**)p0, *(char**)p1); +} + +int +vacwrite(VtConn *z, uchar score[VtScoreSize], int type, uchar *buf, int n) +{ + assert(n > 0); + if(nowrite){ + sha1(buf, n, score, nil); + return 0; + } +sha1(buf, n, score, nil); +fprint(2, "write %V %d\n", score, type); + return vtwrite(z, score, type, buf, n); +} + +static char* +lastelem(char *oname) +{ + char *p; + + if(oname == nil) + abort(); + if((p = strrchr(oname, '/')) == nil) + return oname; + return p+1; +} + +static void +vac(VtConn *z, char *argv[]) { DirSink *dsink, *ds; MetaSink *ms; VtRoot root; uchar score[VtScoreSize], buf[VtRootSize]; char cwd[2048]; - int cd, i; + int cd; char *cp2, *cp; - VacFS *fs; + VacFs *fs; VacFile *vff; int fd; Dir *dir; @@ -79,13 +251,13 @@ vac(VtSession *z, char *argv[]) if(getwd(cwd, sizeof(cwd)) == 0) sysfatal("can't find current directory: %r\n"); - dsink = dirSinkAlloc(z, bsize, bsize); + dsink = dirsinkalloc(z, bsize, bsize); fs = nil; if(dfile != nil) { - fs = vfsOpen(z, dfile, 1, 10000); + fs = vacfsopen(z, dfile, VtOREAD, 1000); if(fs == nil) - fprint(2, "could not open diff: %s: %s\n", dfile, vtGetError()); + fprint(2, "could not open diff: %s: %r\n", dfile); } @@ -99,6 +271,10 @@ vac(VtSession *z, char *argv[]) dir = dirfstat(fd); if(dir == nil) sysfatal("dirfstat failed: %r"); + if(oname) + dir->name = lastelem(oname); + else + dir->name = "stdin"; for(; *argv; argv++) { cp2 = *argv; @@ -115,10 +291,10 @@ vac(VtSession *z, char *argv[]) } vff = nil; if(fs) - vff = vfOpen(fs, cp2); - vacFile(dsink, argv[0], cp2, vff); + vff = vacfileopen(fs, cp2); + vacfile(dsink, argv[0], cp2, vff); if(vff) - vfDecRef(vff); + vacfiledecref(vff); if(cd && chdir(cwd) < 0) sysfatal("can't cd back to %s: %r\n", cwd); } @@ -126,68 +302,63 @@ vac(VtSession *z, char *argv[]) if(isi) { vff = nil; if(fs) - vff = vfOpen(fs, isi); - vacStdin(dsink, isi, vff); + vff = vacfileopen(fs, isi); + vacstdin(dsink, isi, vff); if(vff) - vfDecRef(vff); + vacfiledecref(vff); } - dirSinkClose(dsink); + dirsinkclose(dsink); /* build meta information for the root */ - ms = metaSinkAlloc(z, bsize, bsize); + ms = metasinkalloc(z, bsize, bsize); /* fake into a directory */ dir->mode |= (dir->mode&0444)>>2; dir->qid.type |= QTDIR; dir->mode |= DMDIR; - plan9ToVacDir(&vd, dir, 0, fileid++); + plan9tovacdir(&vd, dir, 0, fileid++); if(strcmp(vd.elem, "/") == 0){ - vtMemFree(vd.elem); - vd.elem = vtStrDup("root"); + vtfree(vd.elem); + vd.elem = vtstrdup("root"); } - metaSinkWriteDir(ms, &vd); - vdCleanup(&vd); - metaSinkClose(ms); + metasinkwritedir(ms, &vd); + vdcleanup(&vd); + metasinkclose(ms); - ds = dirSinkAlloc(z, bsize, bsize); - dirSinkWriteSink(ds, dsink->sink); - dirSinkWriteSink(ds, dsink->msink->sink); - dirSinkWriteSink(ds, ms->sink); - dirSinkClose(ds); + ds = dirsinkalloc(z, bsize, bsize); + dirsinkwritesink(ds, dsink->sink); + dirsinkwritesink(ds, dsink->msink->sink); + dirsinkwritesink(ds, ms->sink); + dirsinkclose(ds); memset(&root, 0, sizeof(root)); - root.version = VtRootVersion; strncpy(root.name, dir->name, sizeof(root.name)); root.name[sizeof(root.name)-1] = 0; free(dir); sprint(root.type, "vac"); memmove(root.score, ds->sink->dir.score, VtScoreSize); - root.blockSize = maxbsize; + root.blocksize = maxbsize; if(fs != nil) - vfsGetScore(fs, root.prev); + vacfsgetscore(fs, root.prev); - metaSinkFree(ms); - dirSinkFree(ds); - dirSinkFree(dsink); + metasinkfree(ms); + dirsinkfree(ds); + dirsinkfree(dsink); if(fs != nil) - vfsClose(fs); - - vtRootPack(&root, buf); - if(!vacWrite(z, score, VtRootType, buf, VtRootSize)) - vtFatal("vacWrite failed: %s", vtGetError()); - - fprint(fd, "vac:"); - for(i=0; i<VtScoreSize; i++) - fprint(fd, "%.2x", score[i]); - fprint(fd, "\n"); + vacfsclose(fs); + vtrootpack(&root, buf); + if(vacwrite(z, score, VtRootType, buf, VtRootSize) < 0) + sysfatal("vacWrite failed: %r"); + + fprint(fd, "vac:%V\n", score); + /* avoid remove at cleanup */ oname = nil; - return 1; } static int -isExcluded(char *name) +isexcluded(char *name) { int bot, top, i, x; @@ -207,24 +378,24 @@ isExcluded(char *name) } static void -vacFile(DirSink *dsink, char *lname, char *sname, VacFile *vf) +vacfile(DirSink *dsink, char *lname, char *sname, VacFile *vf) { int fd; Dir *dir; VacDir vd; ulong entry; - if(isExcluded(lname)) { + if(isexcluded(lname)) { warn("excluding: %s", lname); return; } - if(merge && vacMerge(dsink, lname, sname)) + if(merge && vacmerge(dsink, lname, sname) >= 0) return; fd = open(sname, OREAD); if(fd < 0) { - warn("could not open file: %s: %s", lname, vtOSError()); + warn("could not open file: %s: %r", lname); return; } @@ -237,24 +408,25 @@ vacFile(DirSink *dsink, char *lname, char *sname, VacFile *vf) close(fd); return; } + dir->name = lastelem(sname); entry = dsink->nentry; if(dir->mode & DMDIR) - vacDir(dsink, fd, lname, sname, vf); + vacdir(dsink, fd, lname, sname, vf); else - vacData(dsink, fd, lname, vf, dir); + vacdata(dsink, fd, lname, vf, dir); - plan9ToVacDir(&vd, dir, entry, fileid++); - metaSinkWriteDir(dsink->msink, &vd); - vdCleanup(&vd); + plan9tovacdir(&vd, dir, entry, fileid++); + metasinkwritedir(dsink->msink, &vd); + vdcleanup(&vd); free(dir); close(fd); } static void -vacStdin(DirSink *dsink, char *name, VacFile *vf) +vacstdin(DirSink *dsink, char *name, VacFile *vf) { Dir *dir; VacDir vd; @@ -268,21 +440,33 @@ vacStdin(DirSink *dsink, char *name, VacFile *vf) warn("can't stat <stdio>: %r"); return; } + dir->name = "stdin"; entry = dsink->nentry; - vacData(dsink, 0, "<stdin>", vf, dir); + vacdata(dsink, 0, "<stdin>", vf, dir); - plan9ToVacDir(&vd, dir, entry, fileid++); - vd.elem = vtStrDup(name); - metaSinkWriteDir(dsink->msink, &vd); - vdCleanup(&vd); + plan9tovacdir(&vd, dir, entry, fileid++); + vd.elem = vtstrdup(name); + metasinkwritedir(dsink->msink, &vd); + vdcleanup(&vd); free(dir); } +static int +sha1check(u8int *score, uchar *buf, int n) +{ + char score2[VtScoreSize]; + + sha1(buf, n, score, nil); + if(memcmp(score, score2, VtScoreSize) == 0) + return 0; + return -1; +} + static ulong -vacDataSkip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lname) +vacdataskip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lname) { int n; ulong i; @@ -293,24 +477,24 @@ vacDataSkip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lna warn("error seeking: %s", lname); goto Err; } - n = readBlock(fd, buf, bsize); + n = readn(fd, buf, bsize); if(n < bsize) { warn("error checking append only file: %s", lname); goto Err; } - if(!vfGetBlockScore(vf, blocks-1, score) || !vtSha1Check(score, buf, n)) { + if(vacfileblockscore(vf, blocks-1, score)<0 || sha1check(score, buf, n)<0) { warn("last block of append file did not match: %s", lname); goto Err; } for(i=0; i<blocks; i++) { - if(!vfGetBlockScore(vf, i, score)) { + if(vacfileblockscore(vf, i, score) < 0) { warn("could not get score: %s: %lud", lname, i); seek(fd, i*bsize, 0); return i; } stats.skip++; - sinkWriteScore(sink, score, bsize); + sinkwritescore(sink, score, bsize); } return i; @@ -320,7 +504,7 @@ Err: } static void -vacData(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir) +vacdata(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir) { uchar *buf; Sink *sink; @@ -332,13 +516,13 @@ vacData(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir) vfblocks = 0; if(vf != nil && qdiff) { - vfGetDir(vf, &vd); + vacfilegetdir(vf, &vd); if(vd.mtime == dir->mtime) if(vd.size == dir->length) if(!vd.plan9 || /* vd.p9path == dir->qid.path && */ vd.p9version == dir->qid.vers) - if(dirSinkWriteFile(dsink, vf)) { + if(dirsinkwritefile(dsink, vf)) { stats.sfile++; - vdCleanup(&vd); + vdcleanup(&vd); return; } @@ -349,30 +533,30 @@ vacData(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir) if(vd.p9path == dir->qid.path) vfblocks = vd.size/bsize; - vdCleanup(&vd); + vdcleanup(&vd); } stats.file++; - buf = vtMemAlloc(bsize); - sink = sinkAlloc(dsink->sink->z, bsize, bsize); + buf = vtmalloc(bsize); + sink = sinkalloc(dsink->sink->z, bsize, bsize); block = 0; same = stats.sdata+stats.skip; if(vfblocks > 1) - block += vacDataSkip(sink, vf, fd, vfblocks, buf, lname); + block += vacdataskip(sink, vf, fd, vfblocks, buf, lname); if(0) fprint(2, "vacData: %s: %ld\n", lname, block); for(;;) { - n = readBlock(fd, buf, bsize); + n = readn(fd, buf, bsize); if(0 && n < 0) - warn("file truncated due to read error: %s: %s", lname, vtOSError()); + warn("file truncated due to read error: %s: %r", lname); if(n <= 0) break; - if(vf != nil && vfGetBlockScore(vf, block, score) && vtSha1Check(score, buf, n)) { + if(vf != nil && vacfileblockscore(vf, block, score) && sha1check(score, buf, n)>=0) { stats.sdata++; - sinkWriteScore(sink, score, n); + sinkwritescore(sink, score, n); } else - sinkWrite(sink, buf, n); + sinkwrite(sink, buf, n); block++; } same = stats.sdata+stats.skip - same; @@ -381,15 +565,15 @@ if(0) fprint(2, "vacData: %s: %ld\n", lname, block); if(0)fprint(2, "%s: total %lud same %lud:%lud diff %lud\n", lname, block, same, vfblocks, block-same); - sinkClose(sink); - dirSinkWriteSink(dsink, sink); - sinkFree(sink); + sinkclose(sink); + dirsinkwritesink(dsink, sink); + sinkfree(sink); free(buf); } static void -vacDir(DirSink *dsink, int fd, char *lname, char *sname, VacFile *vf) +vacdir(DirSink *dsink, int fd, char *lname, char *sname, VacFile *vf) { Dir *dirs; char *ln, *sn; @@ -398,58 +582,58 @@ vacDir(DirSink *dsink, int fd, char *lname, char *sname, VacFile *vf) VacFile *vvf; char *name; - ds = dirSinkAlloc(dsink->sink->z, bsize, bsize); + ds = dirsinkalloc(dsink->sink->z, bsize, bsize); while((nd = dirread(fd, &dirs)) > 0){ for(i = 0; i < nd; i++){ name = dirs[i].name; /* check for bad file names */ if(name[0] == 0 || strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue; - ln = vtMemAlloc(strlen(lname) + strlen(name) + 2); - sn = vtMemAlloc(strlen(sname) + strlen(name) + 2); + ln = vtmalloc(strlen(lname) + strlen(name) + 2); + sn = vtmalloc(strlen(sname) + strlen(name) + 2); sprint(ln, "%s/%s", lname, name); sprint(sn, "%s/%s", sname, name); if(vf != nil) - vvf = vfWalk(vf, name); + vvf = vacfilewalk(vf, name); else vvf = nil; - vacFile(ds, ln, sn, vvf); + vacfile(ds, ln, sn, vvf); if(vvf != nil) - vfDecRef(vvf); - vtMemFree(ln); - vtMemFree(sn); + vacfiledecref(vvf); + vtfree(ln); + vtfree(sn); } free(dirs); } - dirSinkClose(ds); - dirSinkWriteSink(dsink, ds->sink); - dirSinkWriteSink(dsink, ds->msink->sink); - dirSinkFree(ds); + dirsinkclose(ds); + dirsinkwritesink(dsink, ds->sink); + dirsinkwritesink(dsink, ds->msink->sink); + dirsinkfree(ds); } static int -vacMergeFile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max) +vacmergefile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max) { uchar buf[VtEntrySize]; VtEntry dd, md; int e; - if(vfRead(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) { + if(vacfileread(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) { warn("could not read venti dir entry: %s\n", dir->elem); - return 0; + return -1; } - vtEntryUnpack(&dd, buf, 0); + vtentryunpack(&dd, buf, 0); if(dir->mode & ModeDir) { e = dir->mentry; if(e == 0) e = dir->entry + 1; - if(vfRead(vf, buf, VtEntrySize, e*VtEntrySize) != VtEntrySize) { + if(vacfileread(vf, buf, VtEntrySize, e*VtEntrySize) != VtEntrySize) { warn("could not read venti dir entry: %s\n", dir->elem); return 0; } - vtEntryUnpack(&md, buf, 0); + vtentryunpack(&md, buf, 0); } /* max might incorrect in some old dumps */ @@ -461,27 +645,27 @@ vacMergeFile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *ma dir->qid += offset; dir->entry = dsink->nentry; - if(dir->qidSpace) { - dir->qidOffset += offset; + if(dir->qidspace) { + dir->qidoffset += offset; } else { - dir->qidSpace = 1; - dir->qidOffset = offset; - dir->qidMax = *max; + dir->qidspace = 1; + dir->qidoffset = offset; + dir->qidmax = *max; } - dirSinkWrite(dsink, &dd); + dirsinkwrite(dsink, &dd); if(dir->mode & ModeDir) - dirSinkWrite(dsink, &md); - metaSinkWriteDir(dsink->msink, dir); + dirsinkwrite(dsink, &md); + metasinkwritedir(dsink->msink, dir); - return 1; + return 0; } static int -vacMerge(DirSink *dsink, char *lname, char *sname) +vacmerge(DirSink *dsink, char *lname, char *sname) { char *p; - VacFS *fs; + VacFs *fs; VacFile *vf; VacDirEnum *d; VacDir dir; @@ -492,67 +676,67 @@ vacMerge(DirSink *dsink, char *lname, char *sname) return 0; d = nil; - fs = vfsOpen(dsink->sink->z, sname, 1, 100); + fs = vacfsopen(dsink->sink->z, sname, VtOREAD, 100); if(fs == nil) - return 0; + return -1; - vf = vfOpen(fs, "/"); + vf = vacfileopen(fs, "/"); if(vf == nil) goto Done; - max = vfGetId(vf); - d = vdeOpen(fs, "/"); + max = vacfilegetid(vf); + d = vdeopen(vf); if(d == nil) goto Done; if(verbose) fprint(2, "merging: %s\n", lname); - if(maxbsize < vfsGetBlockSize(fs)) - maxbsize = vfsGetBlockSize(fs); + if(maxbsize < fs->bsize) + maxbsize = fs->bsize; for(;;) { - if(vdeRead(d, &dir, 1) < 1) + if(vderead(d, &dir) < 1) break; - vacMergeFile(dsink, vf, &dir, fileid, &max); - vdCleanup(&dir); + vacmergefile(dsink, vf, &dir, fileid, &max); + vdcleanup(&dir); } fileid += max; Done: if(d != nil) - vdeFree(d); + vdeclose(d); if(vf != nil) - vfDecRef(vf); - vfsClose(fs); - return 1; + vacfiledecref(vf); + vacfsclose(fs); + return 0; } Sink * -sinkAlloc(VtSession *z, int psize, int dsize) +sinkalloc(VtConn *z, int psize, int dsize) { Sink *k; int i; if(psize < 512 || psize > VtMaxLumpSize) - vtFatal("sinkAlloc: bad psize"); + sysfatal("sinkalloc: bad psize"); if(dsize < 512 || dsize > VtMaxLumpSize) - vtFatal("sinkAlloc: bad psize"); + sysfatal("sinkalloc: bad psize"); psize = VtScoreSize*(psize/VtScoreSize); - k = vtMemAllocZ(sizeof(Sink)); + k = vtmallocz(sizeof(Sink)); k->z = z; k->dir.flags = VtEntryActive; k->dir.psize = psize; k->dir.dsize = dsize; - k->buf = vtMemAllocZ(VtPointerDepth*k->dir.psize + VtScoreSize); + k->buf = vtmallocz(VtPointerDepth*k->dir.psize + VtScoreSize); for(i=0; i<=VtPointerDepth; i++) k->pbuf[i] = k->buf + i*k->dir.psize; return k; } void -sinkWriteScore(Sink *k, uchar score[VtScoreSize], int n) +sinkwritescore(Sink *k, uchar score[VtScoreSize], int n) { int i; uchar *p; @@ -567,11 +751,11 @@ sinkWriteScore(Sink *k, uchar score[VtScoreSize], int n) if(k->pbuf[i] < k->buf + d->psize*(i+1)) break; if(i == VtPointerDepth-1) - vtFatal("file too big"); + sysfatal("file too big"); p = k->buf+i*d->psize; stats.meta++; - if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, d->psize)) - vtFatal("vacWrite failed: %s", vtGetError()); + if(vacwrite(k->z, k->pbuf[i+1], VtDataType+1+i, p, d->psize) < 0) + sysfatal("vacwrite failed: %r"); k->pbuf[i] = p; } @@ -582,29 +766,29 @@ sinkWriteScore(Sink *k, uchar score[VtScoreSize], int n) } void -sinkWrite(Sink *k, uchar *p, int n) +sinkwrite(Sink *k, uchar *p, int n) { int type; uchar score[VtScoreSize]; if(n > k->dir.dsize) - vtFatal("sinkWrite: size too big"); + sysfatal("sinkWrite: size too big"); - if(k->dir.flags & VtEntryDir) { + if((k->dir.type&~VtTypeDepthMask) == VtDirType){ type = VtDirType; stats.meta++; } else { type = VtDataType; stats.data++; } - if(!vacWrite(k->z, score, type, p, n)) - vtFatal("vacWrite failed: %s", vtGetError()); + if(vacwrite(k->z, score, type, p, n) < 0) + sysfatal("vacWrite failed: %r"); - sinkWriteScore(k, score, n); + sinkwritescore(k, score, n); } static int -sizeToDepth(uvlong s, int psize, int dsize) +sizetodepth(uvlong s, int psize, int dsize) { int np; int d; @@ -618,9 +802,9 @@ sizeToDepth(uvlong s, int psize, int dsize) } void -sinkClose(Sink *k) +sinkclose(Sink *k) { - int i, n; + int i, n, base; uchar *p; VtEntry *kd; @@ -628,7 +812,7 @@ sinkClose(Sink *k) /* empty */ if(kd->size == 0) { - memmove(kd->score, vtZeroScore, VtScoreSize); + memmove(kd->score, vtzeroscore, VtScoreSize); return; } @@ -636,7 +820,10 @@ sinkClose(Sink *k) if(k->pbuf[n] > k->buf + kd->psize*n) break; - kd->depth = sizeToDepth(kd->size, kd->psize, kd->dsize); +fprint(2, "type %d -> ", kd->type); + base = kd->type&~VtTypeDepthMask; + kd->type = base + sizetodepth(kd->size, kd->psize, kd->dsize); +fprint(2, "%d ", kd->type); /* skip full part of tree */ for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++) @@ -644,6 +831,7 @@ sinkClose(Sink *k) /* is the tree completely full */ if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) { +fprint(2, "full\n"); memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize); return; } @@ -653,93 +841,95 @@ sinkClose(Sink *k) for(; i<n; i++) { p = k->buf+i*kd->psize; stats.meta++; - if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, k->pbuf[i]-p)) - vtFatal("vacWrite failed: %s", vtGetError()); + if(vacwrite(k->z, k->pbuf[i+1], base+1+i, p, k->pbuf[i]-p) < 0) + sysfatal("vacWrite failed: %r"); k->pbuf[i+1] += VtScoreSize; } memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize); +fprint(2, "%V\n", kd->score); } void -sinkFree(Sink *k) +sinkfree(Sink *k) { - vtMemFree(k->buf); - vtMemFree(k); + vtfree(k->buf); + vtfree(k); } DirSink * -dirSinkAlloc(VtSession *z, int psize, int dsize) +dirsinkalloc(VtConn *z, int psize, int dsize) { DirSink *k; int ds; ds = VtEntrySize*(dsize/VtEntrySize); - k = vtMemAllocZ(sizeof(DirSink)); - k->sink = sinkAlloc(z, psize, ds); - k->sink->dir.flags |= VtEntryDir; - k->msink = metaSinkAlloc(z, psize, dsize); - k->buf = vtMemAlloc(ds); + k = vtmallocz(sizeof(DirSink)); + k->sink = sinkalloc(z, psize, ds); + k->sink->dir.type = VtDirType; + k->msink = metasinkalloc(z, psize, dsize); + k->buf = vtmalloc(ds); k->p = k->buf; k->ep = k->buf + ds; return k; } void -dirSinkWrite(DirSink *k, VtEntry *dir) +dirsinkwrite(DirSink *k, VtEntry *dir) { if(k->p + VtEntrySize > k->ep) { - sinkWrite(k->sink, k->buf, k->p - k->buf); + sinkwrite(k->sink, k->buf, k->p - k->buf); k->p = k->buf; } - vtEntryPack(dir, k->p, 0); +fprint(2, "write entry %V %d\n", dir->score, dir->type); + vtentrypack(dir, k->p, 0); k->nentry++; k->p += VtEntrySize; } void -dirSinkWriteSink(DirSink *k, Sink *sink) +dirsinkwritesink(DirSink *k, Sink *sink) { - dirSinkWrite(k, &sink->dir); + dirsinkwrite(k, &sink->dir); } int -dirSinkWriteFile(DirSink *k, VacFile *vf) +dirsinkwritefile(DirSink *k, VacFile *vf) { VtEntry dir; - if(!vfGetVtEntry(vf, &dir)) - return 0; - dirSinkWrite(k, &dir); - return 1; + if(vacfilegetvtentry(vf, &dir) < 0) + return -1; + dirsinkwrite(k, &dir); + return 0; } void -dirSinkClose(DirSink *k) +dirsinkclose(DirSink *k) { - metaSinkClose(k->msink); + metasinkclose(k->msink); if(k->p != k->buf) - sinkWrite(k->sink, k->buf, k->p - k->buf); - sinkClose(k->sink); + sinkwrite(k->sink, k->buf, k->p - k->buf); + sinkclose(k->sink); } void -dirSinkFree(DirSink *k) +dirsinkfree(DirSink *k) { - sinkFree(k->sink); - metaSinkFree(k->msink); - vtMemFree(k->buf); - vtMemFree(k); + sinkfree(k->sink); + metasinkfree(k->msink); + vtfree(k->buf); + vtfree(k); } -MetaSink * -metaSinkAlloc(VtSession *z, int psize, int dsize) +MetaSink* +metasinkalloc(VtConn *z, int psize, int dsize) { MetaSink *k; - k = vtMemAllocZ(sizeof(MetaSink)); - k->sink = sinkAlloc(z, psize, dsize); - k->buf = vtMemAlloc(dsize); + k = vtmallocz(sizeof(MetaSink)); + k->sink = sinkalloc(z, psize, dsize); + k->buf = vtmalloc(dsize); k->maxindex = dsize/100; /* 100 byte entries seems reasonable */ if(k->maxindex < 1) k->maxindex = 1; @@ -749,22 +939,22 @@ metaSinkAlloc(VtSession *z, int psize, int dsize) } /* hack to get base to compare routine - not reentrant */ -uchar *blockBase; +uchar *blockbase; int -dirCmp(void *p0, void *p1) +dircmp(const void *p0, const void *p1) { uchar *q0, *q1; int n0, n1, r; /* name is first element of entry */ - q0 = p0; - q0 = blockBase + (q0[0]<<8) + q0[1]; + q0 = (uchar*)p0; + q0 = blockbase + (q0[0]<<8) + q0[1]; n0 = (q0[6]<<8) + q0[7]; q0 += 8; - q1 = p1; - q1 = blockBase + (q1[0]<<8) + q1[1]; + q1 = (uchar*)p1; + q1 = blockbase + (q1[0]<<8) + q1[1]; n1 = (q1[6]<<8) + q1[7]; q1 += 8; @@ -780,7 +970,7 @@ dirCmp(void *p0, void *p1) } void -metaSinkFlush(MetaSink *k) +metasinkflush(MetaSink *k) { uchar *p; int n; @@ -798,19 +988,19 @@ metaSinkFlush(MetaSink *k) mb.nindex = k->nindex; mb.maxindex = k->maxindex; mb.buf = p; - mbPack(&mb); + mbpack(&mb); p += MetaHeaderSize; /* XXX this is not reentrant! */ - blockBase = k->buf; - qsort(p, k->nindex, MetaIndexSize, dirCmp); + blockbase = k->buf; + qsort(p, k->nindex, MetaIndexSize, dircmp); p += k->nindex*MetaIndexSize; memset(p, 0, (k->maxindex-k->nindex)*MetaIndexSize); p += (k->maxindex-k->nindex)*MetaIndexSize; - sinkWrite(k->sink, k->buf, n); + sinkwrite(k->sink, k->buf, n); /* move down partial entry */ n = k->p - k->rp; @@ -821,109 +1011,109 @@ metaSinkFlush(MetaSink *k) } void -metaSinkPutc(MetaSink *k, int c) +metasinkputc(MetaSink *k, int c) { if(k->p+1 > k->ep) - metaSinkFlush(k); + metasinkflush(k); if(k->p+1 > k->ep) - vtFatal("directory entry too large"); + sysfatal("directory entry too large"); k->p[0] = c; k->p++; } void -metaSinkPutString(MetaSink *k, char *s) +metasinkputstring(MetaSink *k, char *s) { int n = strlen(s); - metaSinkPutc(k, n>>8); - metaSinkPutc(k, n); - metaSinkWrite(k, (uchar*)s, n); + metasinkputc(k, n>>8); + metasinkputc(k, n); + metasinkwrite(k, (uchar*)s, n); } void -metaSinkPutUint32(MetaSink *k, ulong x) +metasinkputuint32(MetaSink *k, ulong x) { - metaSinkPutc(k, x>>24); - metaSinkPutc(k, x>>16); - metaSinkPutc(k, x>>8); - metaSinkPutc(k, x); + metasinkputc(k, x>>24); + metasinkputc(k, x>>16); + metasinkputc(k, x>>8); + metasinkputc(k, x); } void -metaSinkPutUint64(MetaSink *k, uvlong x) +metasinkputuint64(MetaSink *k, uvlong x) { - metaSinkPutUint32(k, x>>32); - metaSinkPutUint32(k, x); + metasinkputuint32(k, x>>32); + metasinkputuint32(k, x); } void -metaSinkWrite(MetaSink *k, uchar *data, int n) +metasinkwrite(MetaSink *k, uchar *data, int n) { if(k->p + n > k->ep) - metaSinkFlush(k); + metasinkflush(k); if(k->p + n > k->ep) - vtFatal("directory entry too large"); + sysfatal("directory entry too large"); memmove(k->p, data, n); k->p += n; } void -metaSinkWriteDir(MetaSink *ms, VacDir *dir) +metasinkwritedir(MetaSink *ms, VacDir *dir) { - metaSinkPutUint32(ms, DirMagic); - metaSinkPutc(ms, Version>>8); - metaSinkPutc(ms, Version); - metaSinkPutString(ms, dir->elem); - metaSinkPutUint32(ms, dir->entry); - metaSinkPutUint64(ms, dir->qid); - metaSinkPutString(ms, dir->uid); - metaSinkPutString(ms, dir->gid); - metaSinkPutString(ms, dir->mid); - metaSinkPutUint32(ms, dir->mtime); - metaSinkPutUint32(ms, dir->mcount); - metaSinkPutUint32(ms, dir->ctime); - metaSinkPutUint32(ms, dir->atime); - metaSinkPutUint32(ms, dir->mode); + metasinkputuint32(ms, DirMagic); + metasinkputc(ms, Version>>8); + metasinkputc(ms, Version); + metasinkputstring(ms, dir->elem); + metasinkputuint32(ms, dir->entry); + metasinkputuint64(ms, dir->qid); + metasinkputstring(ms, dir->uid); + metasinkputstring(ms, dir->gid); + metasinkputstring(ms, dir->mid); + metasinkputuint32(ms, dir->mtime); + metasinkputuint32(ms, dir->mcount); + metasinkputuint32(ms, dir->ctime); + metasinkputuint32(ms, dir->atime); + metasinkputuint32(ms, dir->mode); if(dir->plan9) { - metaSinkPutc(ms, DirPlan9Entry); /* plan9 extra info */ - metaSinkPutc(ms, 0); /* plan9 extra size */ - metaSinkPutc(ms, 12); /* plan9 extra size */ - metaSinkPutUint64(ms, dir->p9path); - metaSinkPutUint32(ms, dir->p9version); + metasinkputc(ms, DirPlan9Entry); /* plan9 extra info */ + metasinkputc(ms, 0); /* plan9 extra size */ + metasinkputc(ms, 12); /* plan9 extra size */ + metasinkputuint64(ms, dir->p9path); + metasinkputuint32(ms, dir->p9version); } - if(dir->qidSpace != 0) { - metaSinkPutc(ms, DirQidSpaceEntry); - metaSinkPutc(ms, 0); - metaSinkPutc(ms, 16); - metaSinkPutUint64(ms, dir->qidOffset); - metaSinkPutUint64(ms, dir->qidMax); + if(dir->qidspace != 0) { + metasinkputc(ms, DirQidSpaceEntry); + metasinkputc(ms, 0); + metasinkputc(ms, 16); + metasinkputuint64(ms, dir->qidoffset); + metasinkputuint64(ms, dir->qidmax); } if(dir->gen != 0) { - metaSinkPutc(ms, DirGenEntry); - metaSinkPutc(ms, 0); - metaSinkPutc(ms, 4); - metaSinkPutUint32(ms, dir->gen); + metasinkputc(ms, DirGenEntry); + metasinkputc(ms, 0); + metasinkputc(ms, 4); + metasinkputuint32(ms, dir->gen); } - metaSinkEOR(ms); + metasinkeor(ms); } void -plan9ToVacDir(VacDir *vd, Dir *dir, ulong entry, uvlong qid) +plan9tovacdir(VacDir *vd, Dir *dir, ulong entry, uvlong qid) { memset(vd, 0, sizeof(VacDir)); - vd->elem = vtStrDup(dir->name); + vd->elem = vtstrdup(dir->name); vd->entry = entry; vd->qid = qid; - vd->uid = vtStrDup(dir->uid); - vd->gid = vtStrDup(dir->gid); - vd->mid = vtStrDup(dir->muid); + vd->uid = vtstrdup(dir->uid); + vd->gid = vtstrdup(dir->gid); + vd->mid = vtstrdup(dir->muid); vd->mtime = dir->mtime; vd->mcount = 0; vd->ctime = dir->mtime; /* ctime: not available on plan 9 */ @@ -944,7 +1134,7 @@ plan9ToVacDir(VacDir *vd, Dir *dir, ulong entry, uvlong qid) void -metaSinkEOR(MetaSink *k) +metasinkeor(MetaSink *k) { uchar *p; int o, n; @@ -960,22 +1150,22 @@ metaSinkEOR(MetaSink *k) k->rp = k->p; k->nindex++; if(k->nindex == k->maxindex) - metaSinkFlush(k); + metasinkflush(k); } void -metaSinkClose(MetaSink *k) +metasinkclose(MetaSink *k) { - metaSinkFlush(k); - sinkClose(k->sink); + metasinkflush(k); + sinkclose(k->sink); } void -metaSinkFree(MetaSink *k) +metasinkfree(MetaSink *k) { - sinkFree(k->sink); - vtMemFree(k->buf); - vtMemFree(k); + sinkfree(k->sink); + vtfree(k->buf); + vtfree(k); } static void diff --git a/src/cmd/vac/vac.h b/src/cmd/vac/vac.h index 549c441c..28e4706d 100644 --- a/src/cmd/vac/vac.h +++ b/src/cmd/vac/vac.h @@ -1,4 +1,4 @@ -typedef struct VacFS VacFS; +typedef struct VacFs VacFs; typedef struct VacDir VacDir; typedef struct VacFile VacFile; typedef struct VacDirEnum VacDirEnum; @@ -6,7 +6,8 @@ typedef struct VacDirEnum VacDirEnum; /* * Mode bits */ -enum { +enum +{ ModeOtherExec = (1<<0), ModeOtherWrite = (1<<1), ModeOtherRead = (1<<2), @@ -30,7 +31,8 @@ enum { ModeSnapshot = (1<<20), /* read only snapshot */ }; -enum { +enum +{ MetaMagic = 0x5656fc79, MetaHeaderSize = 12, MetaIndexSize = 4, @@ -38,14 +40,16 @@ enum { DirMagic = 0x1c4d9072, }; -enum { +enum +{ DirPlan9Entry = 1, /* not valid in version >= 9 */ DirNTEntry, /* not valid in version >= 9 */ DirQidSpaceEntry, DirGenEntry, /* not valid in version >= 9 */ }; -struct VacDir { +struct VacDir +{ char *elem; /* path element */ ulong entry; /* entry in directory for data */ ulong gen; /* generation of data entry */ @@ -69,58 +73,67 @@ struct VacDir { ulong p9version; /* sub space of qid */ - int qidSpace; - uvlong qidOffset; /* qid offset */ - uvlong qidMax; /* qid maximum */ + int qidspace; + uvlong qidoffset; /* qid offset */ + uvlong qidmax; /* qid maximum */ }; -VacFS *vfsOpen(VtSession *z, char *file, int readOnly, long ncache); -VacFS *vfsCreate(VtSession *z, int bsize, long ncache); -int vfsGetBlockSize(VacFS*); -int vfsIsReadOnly(VacFS*); -VacFile *vfsGetRoot(VacFS*); -long vfsGetCacheSize(VacFS*); -int vfsSetCacheSize(VacFS*, long); -int vfsSnapshot(VacFS*, char *src, char *dst); -int vfsSync(VacFS*); -int vfsClose(VacFS*); -int vfsGetScore(VacFS*, uchar score[VtScoreSize]); +struct VacFs +{ + int ref; + uchar score[VtScoreSize]; + VacFile *root; + VtConn *z; + int mode; + int bsize; + uvlong qid; + VtCache *cache; +}; + +VacFs *vacfsopen(VtConn *z, char *file, int mode, int ncache); +VacFs *vacfsopenscore(VtConn *z, u8int *score, int mode, int ncache); +VacFs *vacfscreate(VtConn *z, int bsize, int ncache); +void vacfsclose(VacFs *fs); +int vacfssync(VacFs *fs); +int vacfssnapshot(VacFs *fs, char *src, char *dst); +int vacfsgetscore(VacFs *fs, u8int *score); /* * other ideas * - * VacFS *vfsSnapshot(VacFS*, char *src); - * int vfsGraft(VacFS*, char *name, VacFS*); + * VacFs *vfsSnapshot(VacFs*, char *src); + * int vfsGraft(VacFs*, char *name, VacFs*); */ -VacFile *vfOpen(VacFS*, char *path); -VacFile *vfCreate(VacFile*, char *elem, ulong perm, char *user); -VacFile *vfWalk(VacFile*, char *elem); -int vfRemove(VacFile*, char*); -int vfRead(VacFile*, void *, int n, vlong offset); -int vfWrite(VacFile*, void *, int n, vlong offset, char *user); -int vfReadPacket(VacFile*, Packet**, vlong offset); -int vfWritePacket(VacFile*, Packet*, vlong offset, char *user); -uvlong vfGetId(VacFile*); -ulong vfGetMcount(VacFile*); -int vfIsDir(VacFile*); -int vfGetBlockScore(VacFile*, ulong bn, uchar score[VtScoreSize]); -int vfGetSize(VacFile*, uvlong *size); -int vfGetDir(VacFile*, VacDir*); -int vfSetDir(VacFile*, VacDir*); -int vfGetVtEntry(VacFile*, VtEntry*); -VacFile *vfGetParent(VacFile*); -int vfSync(VacFile*); -VacFile *vfIncRef(VacFile*); -void vfDecRef(VacFile*); -VacDirEnum *vfDirEnum(VacFile*); -int vfIsRoot(VacFile *vf); +VacFile *vacfileopen(VacFs *fs, char *path); +VacFile *vacfilecreate(VacFile *file, char *elem, ulong perm, char *muid); +VacFile *vacfilewalk(VacFile *file, char *elem); +int vacfileremove(VacFile *file, char *muid); +int vacfileread(VacFile *file, void *buf, int n, vlong offset); +int vacfileblockscore(VacFile *file, u32int, u8int*); +int vacfilewrite(VacFile *file, void *buf, int n, vlong offset, char *muid); +int vacfilereadpacket(VacFile *file, Packet **pp, vlong offset); +int vacfilewritepacket(VacFile *file, Packet *p, vlong offset, char *muid); +uvlong vacfilegetid(VacFile *file); +ulong vacfilegetmcount(VacFile *file); +int vacfileisdir(VacFile *file); +int vacfileisroot(VacFile *file); +int vacfilegetblocksize(VacFile *file, u32int bn, u8int *score); +int vacfilegetsize(VacFile *file, uvlong *size); +int vacfilegetdir(VacFile *file, VacDir *dir); +int vacfilesetdir(VacFile *file, VacDir *dir, char *muid); +int vacfilegetvtentry(VacFile *file, VtEntry *entry); +VacFile *vacfilegetparent(VacFile *file); +int vacfilesync(VacFile*); +VacFile *vacfileincref(VacFile*); +int vacfiledecref(VacFile*); + +void vdcleanup(VacDir *dir); +void vdcopy(VacDir *dst, VacDir *src); -void vdCleanup(VacDir *dir); -void vdCopy(VacDir *dst, VacDir *src); -VacDirEnum *vdeOpen(VacFS*, char *path); -int vdeRead(VacDirEnum*, VacDir *, int n); -void vdeFree(VacDirEnum*); +VacDirEnum *vdeopen(VacFile*); +int vderead(VacDirEnum*, VacDir *); +void vdeclose(VacDirEnum*); diff --git a/src/cmd/vac/vtdump.c b/src/cmd/vac/vtdump.c index 963e4689..daabedc6 100644 --- a/src/cmd/vac/vtdump.c +++ b/src/cmd/vac/vtdump.c @@ -24,20 +24,19 @@ int cmp; int all; int find; uchar fscore[VtScoreSize]; -VtSession *z; +VtConn *z; -int vtGetUint16(uchar *p); -ulong vtGetUint32(uchar *p); -uvlong vtGetUint48(uchar *p); +int vtgetuint16(uchar *p); +ulong vtgetuint32(uchar *p); +uvlong vtgetuint48(uchar *p); void usage(void); -int parseScore(uchar *score, char *buf, int n); -void readRoot(VtRoot*, uchar *score, char *file); -int dumpDir(Source*, int indent); +void readroot(VtRoot*, uchar *score, char *file); +int dumpdir(Source*, int indent); void -main(int argc, char *argv[]) +threadmain(int argc, char *argv[]) { - char *host = nil; + char *host = nil, *pref; uchar score[VtScoreSize]; Source source; uchar buf[VtMaxLumpSize]; @@ -54,7 +53,7 @@ main(int argc, char *argv[]) case 'f': find++; p = ARGF(); - if(p == nil || !parseScore(fscore, p, strlen(p))) + if(p == nil || vtparsescore(p, &pref, fscore) < 0 || !pref || strcmp(pref, "vac") != 0) usage(); break; case 'a': @@ -62,46 +61,33 @@ main(int argc, char *argv[]) break; }ARGEND - vtAttach(); - - bout = vtMemAllocZ(sizeof(Biobuf)); + bout = vtmallocz(sizeof(Biobuf)); Binit(bout, 1, OWRITE); if(argc > 1) usage(); - vtAttach(); - - fmtinstall('V', vtScoreFmt); - fmtinstall('R', vtErrFmt); + fmtinstall('V', vtscorefmt); + fmtinstall('H', encodefmt); - z = vtDial(host, 0); + z = vtdial(host); if(z == nil) - vtFatal("could not connect to server: %s", vtGetError()); + sysfatal("could not connect to server: %r"); - if(!vtConnect(z, 0)) - sysfatal("vtConnect: %r"); + if(vtconnect(z) < 0) + sysfatal("vtconnect: %r"); - readRoot(&root, score, argv[0]); - ver = root.version; - bsize = root.blockSize; + readroot(&root, score, argv[0]); + bsize = root.blocksize; if(!find) { Bprint(bout, "score: %V\n", score); - Bprint(bout, "version: %d\n", ver); Bprint(bout, "name: %s\n", root.name); Bprint(bout, "type: %s\n", root.type); Bprint(bout, "bsize: %d\n", bsize); Bprint(bout, "prev: %V\n", root.prev); } - switch(ver) { - default: - sysfatal("unknown version"); - case VtRootVersion: - break; - } - - n = vtRead(z, root.score, VtDirType, buf, bsize); + n = vtread(z, root.score, VtDirType, buf, bsize); if(n < 0) sysfatal("could not read root dir"); @@ -115,17 +101,16 @@ main(int argc, char *argv[]) source.depth = 0; source.size = n; - dumpDir(&source, 0); + dumpdir(&source, 0); Bterm(bout); - vtClose(z); - vtDetach(); - exits(0); + vthangup(z); + threadexitsall(0); } void -sourcePrint(Source *s, int indent, int entry) +sourceprint(Source *s, int indent, int entry) { int i; uvlong size; @@ -165,11 +150,11 @@ parse(Source *s, uchar *p) VtEntry dir; memset(s, 0, sizeof(*s)); - if(!vtEntryUnpack(&dir, p, 0)) - return 0; + if(vtentryunpack(&dir, p, 0) < 0) + return -1; if(!(dir.flags & VtEntryActive)) - return 1; + return 0; s->active = 1; s->gen = dir.gen; @@ -177,21 +162,23 @@ parse(Source *s, uchar *p) s->dsize = dir.size; s->size = dir.size; memmove(s->score, dir.score, VtScoreSize); - if(dir.flags & VtEntryDir) + if((dir.type&~VtTypeDepthMask) == VtDirType) s->dir = 1; - s->depth = dir.depth; - return 1; - +fprint(2, "sdir %d type %d %.*H\n", s->dir, dir.type, VtEntrySize, p); + s->depth = dir.type&VtTypeDepthMask; + return 0; } int -sourceRead(Source *s, ulong block, uchar *p, int n) +sourceread(Source *s, ulong block, uchar *p, int n) { - uchar buf[VtMaxLumpSize]; + uchar *buf; uchar score[VtScoreSize]; int i, nn, np, type; int elem[VtPointerDepth]; + buf = vtmalloc(VtMaxLumpSize); + memmove(score, s->score, VtScoreSize); np = s->psize/VtScoreSize; @@ -202,17 +189,17 @@ sourceRead(Source *s, ulong block, uchar *p, int n) assert(block == 0); for(i=s->depth-1; i>=0; i--) { - nn = vtRead(z, score, VtPointerType0+i, buf, s->psize); - if(nn < 0) - return -1; - - if(!vtSha1Check(score, buf, nn)) { - vtSetError("vtSha1Check failed on root block"); + nn = vtread(z, score, (s->dir ? VtDirType : VtDataType)+1+i, buf, s->psize); + if(nn < 0){ +fprint(2, "vtread %V %d: %r\n", score, (s->dir ? VtDirType : VtDataType)+1+i); + free(buf); return -1; } - if((elem[i]+1)*VtScoreSize > nn) + if((elem[i]+1)*VtScoreSize > nn){ + free(buf); return 0; + } memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize); } @@ -221,20 +208,20 @@ sourceRead(Source *s, ulong block, uchar *p, int n) else type = VtDataType; - nn = vtRead(z, score, type, p, n); - if(nn < 0) - return -1; - - if(!vtSha1Check(score, p, nn)) { - vtSetError("vtSha1Check failed on root block"); + nn = vtread(z, score, type, p, n); + if(nn < 0){ +fprint(2, "vtread %V %d: %r\n", score, type); +abort(); + free(buf); return -1; } + free(buf); return nn; } void -dumpFileContents(Source *s) +dumpfilecontents(Source *s) { int nb, lb, i, n; uchar buf[VtMaxLumpSize]; @@ -243,9 +230,9 @@ dumpFileContents(Source *s) lb = s->size%s->dsize; for(i=0; i<nb; i++) { memset(buf, 0, s->dsize); - n = sourceRead(s, i, buf, s->dsize); + n = sourceread(s, i, buf, s->dsize); if(n < 0) { - fprint(2, "could not read block: %d: %s\n", i, vtGetError()); + fprint(2, "could not read block: %d: %r\n", i); continue; } if(i < nb-1) @@ -256,42 +243,45 @@ dumpFileContents(Source *s) } void -dumpFile(Source *s, int indent) +dumpfile(Source *s, int indent) { int nb, i, j, n; - uchar buf[VtMaxLumpSize]; + uchar *buf; uchar score[VtScoreSize]; + buf = vtmalloc(VtMaxLumpSize); nb = (s->size + s->dsize - 1)/s->dsize; for(i=0; i<nb; i++) { memset(buf, 0, s->dsize); - n = sourceRead(s, i, buf, s->dsize); + n = sourceread(s, i, buf, s->dsize); if(n < 0) { - fprint(2, "could not read block: %d: %s\n", i, vtGetError()); + fprint(2, "could not read block: %d: %r\n", i); continue; } for(j=0; j<indent; j++) Bprint(bout, " "); - vtSha1(score, buf, n); + sha1(buf, n, score, nil); Bprint(bout, "%4d: size: %ud: %V\n", i, n, score); } + vtfree(buf); } int -dumpDir(Source *s, int indent) +dumpdir(Source *s, int indent) { int pb, ne, nb, i, j, n, entry; - uchar buf[VtMaxLumpSize]; Source ss; + uchar *buf; + buf = vtmalloc(VtMaxLumpSize); pb = s->dsize/VtEntrySize; ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize; nb = (s->size + s->dsize - 1)/s->dsize; for(i=0; i<nb; i++) { memset(buf, 0, s->dsize); - n = sourceRead(s, i, buf, s->dsize); + n = sourceread(s, i, buf, s->dsize); if(n < 0) { - fprint(2, "could not read block: %d: %s\n", i, vtGetError()); + fprint(2, "could not read block: %d: %r\n", i); continue; } for(j=0; j<pb; j++) { @@ -301,63 +291,40 @@ dumpDir(Source *s, int indent) parse(&ss, buf + j * VtEntrySize); if(!find) - sourcePrint(&ss, indent, entry); + sourceprint(&ss, indent, entry); else if(memcmp(ss.score, fscore, VtScoreSize) == 0) { - dumpFileContents(&ss); - return 0; + dumpfilecontents(&ss); + free(buf); + return -1; } if(ss.dir) { - if(!dumpDir(&ss, indent+1)) - return 0; + if(dumpdir(&ss, indent+1) < 0){ + free(buf); + return -1; + } } else if(all) - dumpFile(&ss, indent+1); + dumpfile(&ss, indent+1); } } - return 1; + free(buf); + return 0; } void usage(void) { fprint(2, "%s: [file]\n", argv0); - exits("usage"); -} - -int -parseScore(uchar *score, char *buf, int n) -{ - int i, c; - - memset(score, 0, VtScoreSize); - - if(n < VtScoreSize*2) - return 0; - for(i=0; i<VtScoreSize*2; i++) { - if(buf[i] >= '0' && buf[i] <= '9') - c = buf[i] - '0'; - else if(buf[i] >= 'a' && buf[i] <= 'f') - c = buf[i] - 'a' + 10; - else if(buf[i] >= 'A' && buf[i] <= 'F') - c = buf[i] - 'A' + 10; - else { - return 0; - } - - if((i & 1) == 0) - c <<= 4; - - score[i>>1] |= c; - } - return 1; + threadexits("usage"); } void -readRoot(VtRoot *root, uchar *score, char *file) +readroot(VtRoot *root, uchar *score, char *file) { int fd; - uchar buf[VtRootSize]; - int i, n, nn; + char *pref; + char buf[VtRootSize]; + int n, nn; if(file == 0) fd = 0; @@ -369,23 +336,17 @@ readRoot(VtRoot *root, uchar *score, char *file) n = readn(fd, buf, sizeof(buf)-1); if(n < 0) sysfatal("read failed: %r\n"); - buf[n] = 0; + if(n==0 || buf[n-1] != '\n') + sysfatal("not a root file"); + buf[n-1] = 0; close(fd); - for(i=0; i<n; i++) { - if(!parseScore(score, (char*)(buf+i), n-i)) - continue; - nn = vtRead(z, score, VtRootType, buf, VtRootSize); - if(nn >= 0) { - if(nn != VtRootSize) - sysfatal("vtRead on root too short"); - if(!vtSha1Check(score, buf, VtRootSize)) - sysfatal("vtSha1Check failed on root block"); - if(!vtRootUnpack(root, buf)) - sysfatal("could not parse root: %r"); - return; - } + if(vtparsescore(buf, &pref, score) < 0){ + sysfatal("not a root file"); } - - sysfatal("could not find root"); + nn = vtread(z, score, VtRootType, buf, VtRootSize); + if(nn < 0) + sysfatal("cannot read root %V", score); + if(vtrootunpack(root, buf) < 0) + sysfatal("cannot parse root: %r"); } |