172 lines · 3.3 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <diskfs.h>#include <venti.h> extern void vtlibthread(void); typedef struct DiskVenti DiskVenti;struct DiskVenti{	Disk disk;	VtEntry e;	VtCache *c;}; extern int nfilereads;extern void _nfilereads_darwin_sucks(void); /* * This part is like file.c but doesn't require storing the root block * in the cache permanently and doesn't care about locking since * all the blocks are read-only.  Perhaps at some point this functionality * should go into libvac in some form. */static intvtfileindices(VtEntry *e, u32int bn, int *index){	int i, np; 	memset(index, 0, VtPointerDepth*sizeof(int)); 	np = e->psize/VtScoreSize;	memset(index, 0, sizeof(index));	for(i=0; bn > 0; i++){		if(i >= VtPointerDepth){			werrstr("bad block number %lud", (ulong)bn);			return -1;		}		index[i] = bn % np;		bn /= np;	}	return i;} VtBlock *_vtfileblock(VtCache*, VtEntry*, u32int);	/* avoid auto-inline by putting later in file */static voiddiskventiblockput(Block *b){	vtblockput(b->priv);	free(b);} static Block*diskventiread(Disk *dd, u32int len, u64int offset){	DiskVenti *d = (DiskVenti*)dd;	VtBlock *vb;	Block *b;	int frag; nfilereads++;	vb = _vtfileblock(d->c, &d->e, offset/d->e.dsize);	if(vb == nil)		return nil; 	b = mallocz(sizeof(Block), 1);	if(b == nil){		vtblockput(vb);		return nil;	} 	b->priv = vb;	b->_close = diskventiblockput;	frag = offset%d->e.dsize;	b->data = (uchar*)vb->data + frag;	b->len = d->e.dsize - frag;	if(b->len > len)		b->len = len;	return b;} VtBlock*_vtfileblock(VtCache *c, VtEntry *e, u32int bn){	VtBlock *b;	int i, d, index[VtPointerDepth+1], t;	uchar score[VtScoreSize]; 	i = vtfileindices(e, bn, index);	if(i < 0)		return nil;	d = (e->type&VtTypeDepthMask);	if(i > d){		werrstr("bad address %d > %d (%x %x)", i, d, e->type, e->flags);		return nil;	} /*fprint(2, "vtread %V\n", e->score); */	b = vtcacheglobal(c, e->score, e->type, d == 0 ? e->dsize : e->psize);	for(i=d-1; i>=0 && b; i--){		t = VtDataType+i;/*fprint(2, "vtread %V\n", b->data+index[i]*VtScoreSize); */		memmove(score, b->data+index[i]*VtScoreSize, VtScoreSize);		vtblockput(b);		b = vtcacheglobal(c, score, t, i == 0 ? e->dsize : e->psize);	}	return b;} static voiddiskventiclose(Disk *dd){	DiskVenti *d = (DiskVenti*)dd;	free(d);} static u64intdiskventisize(Disk *dd){	DiskVenti *d = (DiskVenti*)dd; 	return d->e.size;} Disk*diskopenventi(VtCache *c, uchar score[VtScoreSize]){	DiskVenti *d;	VtEntry e;	VtRoot root;	VtBlock *b; 	if((b = vtcacheglobal(c, score, VtRootType, VtRootSize)) == nil)		goto Err;	if(vtrootunpack(&root, b->data) < 0)		goto Err;	if(root.blocksize < 512 || (root.blocksize&(root.blocksize-1))){		werrstr("bad blocksize %d", root.blocksize);		goto Err;	}	vtblockput(b); 	if((b = vtcacheglobal(c, root.score, VtDirType, VtEntrySize)) == nil)		goto Err;	if(vtentryunpack(&e, b->data, 0) < 0)		goto Err;	vtblockput(b);	b = nil;	if((e.type&VtTypeBaseMask) != VtDataType){		werrstr("not a single file");		goto Err;	} 	d = mallocz(sizeof(DiskVenti), 1);	if(d == nil)		goto Err; 	d->disk._read = diskventiread;	d->disk._close = diskventiclose;	d->disk._size = diskventisize;	d->e = e;	d->c = c;	return &d->disk; Err:	if(b)		vtblockput(b); 	_nfilereads_darwin_sucks();  /* force Darwin ld to pull in file.o */	return nil;}