Vac works.

This commit is contained in:
rsc 2004-03-15 01:56:49 +00:00
parent 333c1dccc2
commit 3d77c87e81
14 changed files with 2459 additions and 2994 deletions

View file

@ -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;
}

View file

@ -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*);

View file

@ -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";

View file

@ -12,3 +12,5 @@ extern char ERemoved[];
extern char ENotEmpty[];
extern char EExists[];
extern char ERoot[];
extern char ENoFile[];
extern char EBadPath[];

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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);
}

View file

@ -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=\

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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

View file

@ -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*);

View file

@ -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");
}