⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 source.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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, 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, "%s: bad flags %#ux %V\n", argv0, 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, "%s: depth == 0! size = %ulld\n", argv0, 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, "%s: sourceOpen: %V:%d: %lud\n", argv0, 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;}voidsourceRemove(Source *r){	lumpFreeEntry(r->lump, r->entry);	sourceFree(r);}intsourceSetDepth(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;}intsourceGetVtEntry(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;}uvlongsourceGetSize(Source *r){	uvlong size;	vtLock(r->lk);	size = r->size;	vtUnlock(r->lk);	return size;}intsourceSetSize(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;}intsourceSetDirSize(Source *r, ulong ds){	uvlong size;	size = (uvlong)r->dsize*(ds/r->epb);	size += VtEntrySize*(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)/VtEntrySize;	return ds;}ulongsourceGetNumBlocks(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, "%s: sourceGetLump: %V:%d %lud\n", argv0, 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);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -