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

📄 vac.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include "stdinc.h"typedef struct MetaChunk MetaChunk;struct MetaChunk {	ushort offset;	ushort size;	ushort index;};static int stringUnpack(char **s, uchar **p, int *n);static int meCmp(MetaEntry*, char *s);static int meCmpOld(MetaEntry*, char *s);static char EBadMeta[] = "corrupted meta data";static char ENoFile[] = "file does not exist";/* * integer conversion routines */#define	U8GET(p)	((p)[0])#define	U16GET(p)	(((p)[0]<<8)|(p)[1])#define	U32GET(p)	(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])#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	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 intstringUnpack(char **s, uchar **p, int *n){	int nn;	if(*n < 2)		return 0;	nn = U16GET(*p);	*p += 2;	*n -= 2;	if(nn > *n)		return 0;	*s = vtMemAlloc(nn+1);	memmove(*s, *p, nn);	(*s)[nn] = 0;	*p += nn;	*n -= nn;	return 1;}static intstringPack(char *s, uchar *p){	int n;	n = strlen(s);	U16PUT(p, n);	memmove(p+2, s, n);	return n+2;}intmbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me){	int i;	int b, t, x;if(0)fprint(2, "mbSearch %s\n", elem);	/* binary search within block */	b = 0;	t = mb->nindex;	while(b < t){		i = (b+t)>>1;		meUnpack(me, mb, i);		if(mb->botch)			x = meCmpOld(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));	vtSetError(ENoFile);	return 0;}voidmbInit(MetaBlock *mb, uchar *p, int n, int ne){	memset(p, 0, n);	mb->maxsize = n;	mb->maxindex = ne;	mb->nindex = 0;	mb->free = 0;	mb->size = MetaHeaderSize + ne*MetaIndexSize;	mb->buf = p;	mb->botch = 0;}intmbUnpack(MetaBlock *mb, uchar *p, int n){	u32int magic;	int i;	int eo, en, omin;	uchar *q;	mb->maxsize = n;	mb->buf = p;	if(n == 0){		memset(mb, 0, sizeof(MetaBlock));		return 1;	}	magic = U32GET(p);	if(magic != MetaMagic && magic != MetaMagic-1)		goto Err;	mb->size = U16GET(p+4);	mb->free = U16GET(p+6);	mb->maxindex = U16GET(p+8);	mb->nindex = U16GET(p+10);	mb->botch = magic != MetaMagic;	if(mb->size > n)		goto Err;	omin = MetaHeaderSize + mb->maxindex*MetaIndexSize;	if(n < omin)		goto Err;	p += MetaHeaderSize;	/* check the index table - ensures that meUnpack and meCmp never fail */	for(i=0; i<mb->nindex; i++){		eo = U16GET(p);		en = U16GET(p+2);		if(eo < omin || eo+en > mb->size || en < 8)			goto Err;		q = mb->buf + eo;		if(U32GET(q) != DirMagic)			goto Err;		p += 4;	}	return 1;Err:	vtSetError(EBadMeta);	return 0;}voidmbPack(MetaBlock *mb){	uchar *p;	p = mb->buf;	assert(!mb->botch);	U32PUT(p, MetaMagic);	U16PUT(p+4, mb->size);	U16PUT(p+6, mb->free);	U16PUT(p+8, mb->maxindex);	U16PUT(p+10, mb->nindex);}voidmbDelete(MetaBlock *mb, int i){	uchar *p;	int n;	MetaEntry me;	assert(i < mb->nindex);	meUnpack(&me, mb, i);	memset(me.p, 0, me.size);	if(me.p - mb->buf + me.size == mb->size)		mb->size -= me.size;	else		mb->free += me.size;	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;	n = (mb->nindex-i-1)*MetaIndexSize;	memmove(p, p+MetaIndexSize, n);	memset(p+n, 0, MetaIndexSize);	mb->nindex--;}voidmbInsert(MetaBlock *mb, int i, MetaEntry *me){	uchar *p;	int o, n;	assert(mb->nindex < mb->maxindex);	o = me->p - mb->buf;	n = me->size;	if(o+n > mb->size){		mb->free -= mb->size - o;		mb->size = o + n;	}else		mb->free -= n;	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;	n = (mb->nindex-i)*MetaIndexSize;	memmove(p+MetaIndexSize, p, n);	U16PUT(p, me->p - mb->buf);	U16PUT(p+2, me->size);	mb->nindex++;}intmbResize(MetaBlock *mb, MetaEntry *me, int n){	uchar *p, *ep;	/* easy case */	if(n <= me->size){		me->size = n;		return 1;	}	/* 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 1;	}	p = mbAlloc(mb, n);	if(p != nil){		me->p = p;		me->size = n;		return 1;	}	return 0;}voidmeUnpack(MetaEntry *me, MetaBlock *mb, int i){	uchar *p;	int eo, en;	assert(i >= 0 && i < mb->nindex);	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;	eo = U16GET(p);	en = U16GET(p+2);	me->p = mb->buf + eo;	me->size = en;	/* checked by mbUnpack */	assert(me->size >= 8);}/* assumes a small amount of checking has been done in mbEntry */static intmeCmp(MetaEntry *me, char *s){	int n;	uchar *p;	p = me->p;	/* skip magic & version */	p += 6;	n = U16GET(p);	p += 2;	if(n > me->size - 8)		n = me->size - 8;	while(n > 0){		if(*s == 0)			return 1;		if(*p < (uchar)*s)			return -1;		if(*p > (uchar)*s)			return 1;		p++;		s++;		n--;	}	return -(*s != 0);}/* * This is the old and broken meCmp. * This cmp routine reverse the sense of the comparison * when one string is a prefix of the other. * In other words, it put "ab" after "abc" rather * than before.  This behaviour is ok; binary search * and sort still work.  However, it is goes against * the usual convention. */static intmeCmpOld(MetaEntry *me, char *s){	int n;	uchar *p;	p = me->p;	/* skip magic & version */	p += 6;	n = U16GET(p);	p += 2;	if(n > me->size - 8)		n = me->size - 8;	while(n > 0){		if(*s == 0)			return -1;		if(*p < (uchar)*s)			return -1;		if(*p > (uchar)*s)			return 1;		p++;		s++;		n--;	}	return *s != 0;}static intoffsetCmp(void *s0, void *s1){	MetaChunk *mc0, *mc1;	mc0 = s0;	mc1 = s1;	if(mc0->offset < mc1->offset)		return -1;	if(mc0->offset > mc1->offset)		return 1;	return 0;}static MetaChunk *metaChunks(MetaBlock *mb){	MetaChunk *mc;	int oo, o, n, i;	uchar *p;	mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));	p = mb->buf + MetaHeaderSize;	for(i = 0; i<mb->nindex; i++){		mc[i].offset = U16GET(p);		mc[i].size = U16GET(p+2);		mc[i].index = i;		p += MetaIndexSize;	}	qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);	/* check block looks ok */	oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;	o = oo;	n = 0;	for(i=0; i<mb->nindex; i++){		o = mc[i].offset;		n = mc[i].size;		if(o < oo)			goto Err;		oo += n;	}	if(o+n > mb->size)		goto Err;	if(mb->size - oo != mb->free)		goto Err;	return mc;Err:fprint(2, "metaChunks failed!\n");oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;for(i=0; i<mb->nindex; i++){fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size);oo += mc[i].size;}fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo);	vtSetError(EBadMeta);	vtMemFree(mc);	return nil;}static voidmbCompact(MetaBlock *mb, MetaChunk *mc){	int oo, o, n, i;	oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;	for(i=0; i<mb->nindex; i++){		o = mc[i].offset;		n = mc[i].size;		if(o != oo){			memmove(mb->buf + oo, mb->buf + o, n);			U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);		}		oo += n;	}	mb->size = oo;	mb->free = 0;}uchar *mbAlloc(MetaBlock *mb, int n){	int i, o;	MetaChunk *mc;	/* off the end */	if(mb->maxsize - mb->size >= n)		return mb->buf + mb->size;	/* check if possible */	if(mb->maxsize - mb->size + mb->free < n)		return nil;	mc = metaChunks(mb);	if(mc == nil){fprint(2, "mbAlloc: metaChunks failed: %r\n");		return nil;	}	/* look for hole */	o = MetaHeaderSize + mb->maxindex*MetaIndexSize;	for(i=0; i<mb->nindex; i++){		if(mc[i].offset - o >= n){			vtMemFree(mc);			return mb->buf + o;		}		o = mc[i].offset + mc[i].size;	}	if(mb->maxsize - o >= n){		vtMemFree(mc);		return mb->buf + o;	}	/* compact and return off the end */	mbCompact(mb, mc);	vtMemFree(mc);	if(mb->maxsize - mb->size < n){		vtSetError(EBadMeta);		return nil;	}	return mb->buf + mb->size;}intdeSize(DirEntry *dir){	int n;	/* constant part */	n = 	4 +	/* magic */		2 + 	/* version */		4 +	/* entry */		4 + 	/* guid */		4 + 	/* mentry */		4 + 	/* mgen */		8 +	/* qid */		4 + 	/* mtime */		4 + 	/* mcount */		4 + 	/* ctime */		4 + 	/* atime */		4 +	/* mode */		0;	/* strings */	n += 2 + strlen(dir->elem);	n += 2 + strlen(dir->uid);	n += 2 + strlen(dir->gid);	n += 2 + strlen(dir->mid);	/* optional sections */	if(dir->qidSpace){		n += 	3 + 	/* option header */			8 + 	/* qidOffset */			8;	/* qid Max */	}	return n;}voiddePack(DirEntry *dir, MetaEntry *me){	uchar *p;	ulong t32;	p = me->p;	U32PUT(p, DirMagic);	U16PUT(p+4, 9);		/* version */	p += 6;	p += stringPack(dir->elem, p);	U32PUT(p, dir->entry);	U32PUT(p+4, dir->gen);	U32PUT(p+8, dir->mentry);	U32PUT(p+12, dir->mgen);	U64PUT(p+16, dir->qid, t32);	p += 24;	p += stringPack(dir->uid, p);	p += stringPack(dir->gid, p);	p += stringPack(dir->mid, p);	U32PUT(p, dir->mtime);	U32PUT(p+4, dir->mcount);	U32PUT(p+8, dir->ctime);	U32PUT(p+12, dir->atime);	U32PUT(p+16, dir->mode);	p += 5*4;	if(dir->qidSpace){		U8PUT(p, DeQidSpace);		U16PUT(p+1, 2*8);		p += 3;		U64PUT(p, dir->qidOffset, t32);		U64PUT(p+8, dir->qidMax, t32);		p += 16;	}	assert(p == me->p + me->size);}intdeUnpack(DirEntry *dir, MetaEntry *me){	int t, nn, n, version;	uchar *p;	p = me->p;	n = me->size;	memset(dir, 0, sizeof(DirEntry));if(0)print("deUnpack\n");	/* magic */	if(n < 4 || U32GET(p) != DirMagic)		goto Err;	p += 4;	n -= 4;if(0)print("deUnpack: got magic\n");	/* version */	if(n < 2)		goto Err;	version = U16GET(p);	if(version < 7 || version > 9)		goto Err;	p += 2;	n -= 2;if(0)print("deUnpack: got version\n");	/* elem */	if(!stringUnpack(&dir->elem, &p, &n))		goto Err;if(0)print("deUnpack: got elem\n");	/* entry  */	if(n < 4)		goto Err;	dir->entry = U32GET(p);	p += 4;	n -= 4;if(0)print("deUnpack: got entry\n");	if(version < 9){		dir->gen = 0;		dir->mentry = dir->entry+1;		dir->mgen = 0;	}else{		if(n < 3*4)			goto Err;		dir->gen = U32GET(p);		dir->mentry = U32GET(p+4);		dir->mgen = U32GET(p+8);		p += 3*4;		n -= 3*4;	}if(0)print("deUnpack: got gen etc\n");	/* size is gotten from VtEntry */	dir->size = 0;	/* qid */	if(n < 8)		goto Err;	dir->qid = U64GET(p);	p += 8;	n -= 8;if(0)print("deUnpack: got qid\n");	/* skip replacement */	if(version == 7){		if(n < VtScoreSize)			goto Err;		p += VtScoreSize;		n -= VtScoreSize;	}	/* uid */	if(!stringUnpack(&dir->uid, &p, &n))		goto Err;	/* gid */	if(!stringUnpack(&dir->gid, &p, &n))		goto Err;	/* mid */	if(!stringUnpack(&dir->mid, &p, &n))		goto Err;if(0)print("deUnpack: got ids\n");	if(n < 5*4)		goto Err;	dir->mtime = U32GET(p);	dir->mcount = U32GET(p+4);	dir->ctime = U32GET(p+8);	dir->atime = U32GET(p+12);	dir->mode = U32GET(p+16);	p += 5*4;	n -= 5*4;if(0)print("deUnpack: got times\n");	/* optional meta data */	while(n > 0){		if(n < 3)			goto Err;		t = p[0];		nn = U16GET(p+1);		p += 3;		n -= 3;		if(n < nn)			goto Err;		switch(t){		case DePlan9:			/* not valid in version >= 9 */			if(version >= 9)				break;			if(dir->plan9 || nn != 12)				goto Err;			dir->plan9 = 1;			dir->p9path = U64GET(p);			dir->p9version = U32GET(p+8);			if(dir->mcount == 0)				dir->mcount = dir->p9version;			break;		case DeGen:			/* not valid in version >= 9 */			if(version >= 9)				break;			break;		case DeQidSpace:			if(dir->qidSpace || nn != 16)				goto Err;			dir->qidSpace = 1;			dir->qidOffset = U64GET(p);			dir->qidMax = U64GET(p+8);			break;		}		p += nn;		n -= nn;	}if(0)print("deUnpack: got options\n");	if(p != me->p + me->size)		goto Err;if(0)print("deUnpack: correct size\n");	return 1;Err:if(0)print("deUnpack: XXXXXXXXXXXX EBadMeta\n");	vtSetError(EBadMeta);	deCleanup(dir);	return 0;}voiddeCleanup(DirEntry *dir){	vtMemFree(dir->elem);	dir->elem = nil;	vtMemFree(dir->uid);	dir->uid = nil;	vtMemFree(dir->gid);	dir->gid = nil;	vtMemFree(dir->mid);	dir->mid = nil;}voiddeCopy(DirEntry *dst, DirEntry *src){	*dst = *src;	dst->elem = vtStrDup(src->elem);	dst->uid = vtStrDup(src->uid);	dst->gid = vtStrDup(src->gid);	dst->mid = vtStrDup(src->mid);}

⌨️ 快捷键说明

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