mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-24 11:41:58 +00:00
Vac works.
This commit is contained in:
parent
333c1dccc2
commit
3d77c87e81
14 changed files with 2459 additions and 2994 deletions
|
@ -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;
|
||||
}
|
|
@ -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*);
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -12,3 +12,5 @@ extern char ERemoved[];
|
|||
extern char ENotEmpty[];
|
||||
extern char EExists[];
|
||||
extern char ERoot[];
|
||||
extern char ENoFile[];
|
||||
extern char EBadPath[];
|
||||
|
|
2466
src/cmd/vac/file.c
2466
src/cmd/vac/file.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
187
src/cmd/vac/fs.c
187
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");
|
||||
if(n != VtRootSize){
|
||||
werrstr("vtread on root too short");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if(!vtSha1Check(score, buf, VtRootSize)) {
|
||||
vtSetError("vtSha1Check failed on root block");
|
||||
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])
|
||||
vacfsgetscore(VacFs *fs, u8int *score)
|
||||
{
|
||||
memmove(fs, score, VtScoreSize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
vfsGetCacheSize(VacFS *fs)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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=\
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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*);
|
||||
|
||||
|
|
|
@ -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('H', encodefmt);
|
||||
|
||||
fmtinstall('V', vtScoreFmt);
|
||||
fmtinstall('R', vtErrFmt);
|
||||
|
||||
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");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue