henesyinit from p9fd787fda5 years agoHistory
389 lines · 7.1 KB · C
RawDownload
#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 intsizeToDepth(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, int entry, int readOnly){	Source *r;	int psize, dsize;	uvlong size;	int depth;	VtDirEntry2 *d; 	if(u->size < (entry+1)*VtDirEntrySize2) {fprint(2, "bad bad block size: %d\n", u->size);		vtSetError(ENoDir);		return nil;	}		d = (VtDirEntry2*)(u->data + entry*VtDirEntrySize2);	if(!(d->flag & VtDirEntryActive)) {		vtSetError(ENoDir);		return nil;	}		psize = vtGetUint16(d->psize);	if(psize < 512 || psize > VtMaxLumpSize) {fprint(2, "bad psize: %d\n", psize);		vtSetError(EBadDir);		return nil;	} 	dsize = vtGetUint16(d->dsize);	if(dsize < 512 || dsize > VtMaxLumpSize) {fprint(2, "bad dsize: %d\n", dsize);		vtSetError(EBadDir);		return nil;	}//fprint(2, "psize = %d dsize = %d\n", psize, dsize);		size = vtGetUint48(d->size); 	depth = (d->flag & VtDirEntryDepthMask) >> VtDirEntryDepthShift; 	/* HACK for backwards compatiblity - should go away at some point */	if(depth == 0) {if(size > dsize) fprint(2, "depth == 0! size = %ulld\n", size);		depth = sizeToDepth(size, psize, dsize);	} 	if(depth < sizeToDepth(size, psize, dsize)) {fprint(2, "bad depth: %d %llud\n", depth, size);		vtSetError(EBadDir);		return nil;	} 	r = vtMemAllocZ(sizeof(Source));	r->lk = vtLockAlloc();	r->cache = c;	r->readOnly = readOnly;	r->lump = lumpIncRef(u);	r->entry = entry;	r->gen = vtGetUint32(d->gen);	r->psize = psize;	r->dsize = dsize;	r->dir = (d->flag & VtDirEntryDir) != 0;	r->depth = depth;	r->size2 = size;	r->epb = r->dsize/VtDirEntrySize; 	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, 0);	if(u == nil)		return nil; 	r = sourceAlloc(r->cache, u, entry%r->epb, readOnly);	lumpDecRef(u, 0);	return r;} Source *sourceCreate(Source *r, int psize, int dsize, int isdir){	Source *rr;	int i, j;	ulong entry;	Lump *u;	ulong bn;	VtDirEntry2 *dir;	ulong gen; 	if(r->readOnly) {		vtSetError(EReadOnly);		return nil;	} 	/*	 * first 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++) {			dir = (VtDirEntry*)(u->data + i*VtDirEntrySize);			gen = vtGetUint32(dir->gen);			if((dir->flag&VtDirEntryActive) == 0 && gen != ~0)				goto Found;		}		lumpDecRef(u, 1);		entry = sourceGetDirSize(r);	}Found:	/* found an entry */for(j=4; j<VtDirEntrySize; j++)if(u->data[i*VtDirEntrySize + j] != 0) {fprint(2, "nonzero dir entry!! %V %d %d %x %d\n", u->score, i, j, dir->flag, vtGetUint16(dir->psize));break;}	memset(dir, 0, VtDirEntrySize);	vtPutUint32(dir->gen, gen);	vtPutUint16(dir->psize, psize);	vtPutUint16(dir->dsize, dsize);	dir->flag |= VtDirEntryActive;	if(isdir)		dir->flag |= VtDirEntryDir;	memmove(dir->score, vtZeroScore, VtScoreSize);	sourceSetDirSize(r, bn*r->epb + i + 1);	rr = sourceAlloc(r->cache, u, i, 0);		lumpDecRef(u, 1);	return rr;} voidsourceRemove(Source *r){	lumpFreeEntry(r->lump, r->entry);	sourceFree(r);} intsourceSetDepth(Source *r, uvlong size){	Lump *u, *v;	VtDirEntry2 *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);		u = r->lump;	vtLock(u->lk);	dir = (VtDirEntry2*)(u->data + r->entry*VtDirEntrySize2);	while(r->depth < depth) {		v = cacheAllocLump(r->cache, VtPointerType0+r->depth, r->psize, r->dir);		if(v == nil) {			vtUnlock(u->lk);			vtUnlock(r->lk);			return 0;		}		memmove(v->data, dir->score, VtScoreSize);		memmove(dir->score, v->score, VtScoreSize);		r->depth++;		dir->flag &= ~VtDirEntryDepthMask;		dir->flag |= r->depth << VtDirEntryDepthShift;		vtUnlock(v->lk);	}	vtUnlock(u->lk);	vtUnlock(r->lk);	return 1;} intsourceGetVtDirEntry(Source *r, VtDirEntry *dir){	Lump *u;	memset(dir, 0, sizeof(*dir));	u = r->lump;	vtLock(u->lk);	memmove(dir, u->data + r->entry*VtDirEntrySize, VtDirEntrySize);	vtUnlock(u->lk);	return 1;} uvlongsourceGetSize(Source *r){	uvlong size; 	vtLock(r->lk);	size = r->size2;	vtUnlock(r->lk); 	return size;}  intsourceSetSize(Source *r, uvlong size){	Lump *u;	VtDirEntry2 *dir;	int depth; 	if(r->readOnly) {		vtSetError(EReadOnly);		return 0;	} 	if(size > VtMaxFileSize) {		vtSetError(ETooBig);		return 0;	} 	vtLock(r->lk);	depth = sizeToDepth(size, r->psize, r->dsize);	if(size < r->size2) {		vtUnlock(r->lk);		return 1;	}	if(depth > r->depth) {		vtSetError(EBadDir);		vtUnlock(r->lk);		return 0;	}		u = r->lump;	vtLock(u->lk);	dir = (VtDirEntry2*)(u->data + r->entry*VtDirEntrySize2);	vtPutUint48(dir->size, size);	r->size2 = size;	vtUnlock(u->lk);	vtUnlock(r->lk);	return 1;} intsourceSetDirSize(Source *r, ulong ds){	uvlong size; 	size = (uvlong)r->dsize*(ds/r->epb);	size += VtDirEntrySize*(ds%r->epb);	return sourceSetSize(r, size);} ulongsourceGetDirSize(Source *r){	ulong ds;	uvlong size; 	size = sourceGetSize(r);	ds = r->epb*(size/r->dsize);	ds += (size%r->dsize)/VtDirEntrySize;	return ds;} 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(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;} voidsourceFree(Source *k){	if(k == nil)		return;	lumpDecRef(k->lump, 0);	vtLockFree(k->lk);	memset(k, ~0, sizeof(*k));	vtMemFree(k);}