745 lines · 12.1 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "stdinc.h"#include "vac.h"#include "dat.h"#include "fns.h"#include "error.h" typedef struct MetaChunk MetaChunk; struct MetaChunk {	ushort offset;	ushort size;	ushort index;}; static int	stringunpack(char **s, uchar **p, int *n); /* * 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)&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 intstringunpack(char **s, uchar **p, int *n){	int nn; 	if(*n < 2)		return -1;		nn = U16GET(*p);	*p += 2;	*n -= 2;	if(nn > *n)		return -1;	*s = vtmalloc(nn+1);	memmove(*s, *p, nn);	(*s)[nn] = 0;	*p += nn;	*n -= nn;	return 0;} static intstringpack(char *s, uchar *p){	int n; 	n = strlen(s);	U16PUT(p, n);	memmove(p+2, s, n);	return n+2;}  intmbunpack(MetaBlock *mb, uchar *p, int n){	u32int magic; 	mb->maxsize = n;	mb->buf = p; 	if(n == 0) {		memset(mb, 0, sizeof(MetaBlock));		return 0;	} 	magic = U32GET(p);	if(magic != MetaMagic && magic != MetaMagic+1) {		werrstr("bad meta block magic");		return -1;	}	mb->size = U16GET(p+4);	mb->free = U16GET(p+6);	mb->maxindex = U16GET(p+8);	mb->nindex = U16GET(p+10);	mb->unbotch = (magic == MetaMagic+1); 	if(mb->size > n) {		werrstr("bad meta block size");		return -1;	}	p += MetaHeaderSize;	n -= MetaHeaderSize; 	USED(p);	if(n < mb->maxindex*MetaIndexSize) { 		werrstr("truncated meta block 2");		return -1;	}	return 0;} voidmbpack(MetaBlock *mb){	uchar *p; 	p = mb->buf; 	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, MetaEntry *me){	uchar *p;	int n; 	assert(i < mb->nindex); 	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++;} intmeunpack(MetaEntry *me, MetaBlock *mb, int i){	uchar *p;	int eo, en; 	if(i < 0 || i >= mb->nindex) {		werrstr("bad meta entry index");		return -1;	} 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;	eo = U16GET(p);	en = U16GET(p+2); if(0)print("eo = %d en = %d\n", eo, en);	if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) {		werrstr("corrupted entry in meta block");		return -1;	} 	if(eo+en > mb->size) { 		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)) {		werrstr("corrupted meta block entry");		return -1;	} 	me->p = p;	me->size = en; 	return 0;} /* assumes a small amount of checking has been done in mbentry */intmecmp(MetaEntry *me, char *s){	int n;	uchar *p; 	p = me->p; 	p += 6;	n = U16GET(p);	p += 2; 	assert(n + 8 < me->size); 	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;} intmecmpnew(MetaEntry *me, char *s){	int n;	uchar *p; 	p = me->p; 	p += 6;	n = U16GET(p);	p += 2; 	assert(n + 8 < me->size); 	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(const void *s0, const void *s1){	const 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 = vtmalloc(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:	vtfree(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); 	/* look for hole */	o = MetaHeaderSize + mb->maxindex*MetaIndexSize;	for(i=0; i<mb->nindex; i++) {		if(mc[i].offset - o >= n) {			vtfree(mc);			return mb->buf + o;		}		o = mc[i].offset + mc[i].size;	} 	if(mb->maxsize - o >= n) {		vtfree(mc);		return mb->buf + o;	} 	/* compact and return off the end */	mbcompact(mb, mc);	vtfree(mc); 	assert(mb->maxsize - mb->size >= n);	return mb->buf + mb->size;} intvdsize(VacDir *dir, int version){	int n;		if(version < 8 || version > 9)		sysfatal("bad version %d in vdpack", version); 	/* constant part */	n = 	4 +	/* magic */		2 + 	/* version */		4 +	/* entry */		8 +	/* qid */		4 + 	/* mtime */		4 + 	/* mcount */		4 + 	/* ctime */		4 + 	/* atime */		4 +	/* mode */		0; 	if(version == 9){		n += 	4 +	/* gen */			4 + 	/* mentry */			4 + 	/* mgen */			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(version < 9 && dir->plan9) {		n += 	3 + 	/* option header */			8 + 	/* path */			4;	/* version */	}	if(dir->qidspace) {		n += 	3 + 	/* option header */			8 + 	/* qid offset */			8;	/* qid max */	}	if(version < 9 && dir->gen) {		n += 	3 + 	/* option header */			4;	/* gen */	} 	return n;} voidvdpack(VacDir *dir, MetaEntry *me, int version){	uchar *p;	ulong t32; 	if(version < 8 || version > 9)		sysfatal("bad version %d in vdpack", version); 	p = me->p;		U32PUT(p, DirMagic);	U16PUT(p+4, version);		/* version */	p += 6; 	p += stringpack(dir->elem, p); 	U32PUT(p, dir->entry);	p += 4;		if(version == 9){		U32PUT(p, dir->gen);		U32PUT(p+4, dir->mentry);		U32PUT(p+8, dir->mgen);		p += 12;	} 	U64PUT(p, dir->qid, t32);	p += 8; 	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->plan9 && version < 9) {		U8PUT(p, DirPlan9Entry);		U16PUT(p+1, 8+4);		p += 3;		U64PUT(p, dir->p9path, t32);		U32PUT(p+8, dir->p9version);		p += 12;	} 	if(dir->qidspace) {		U8PUT(p, DirQidSpaceEntry);		U16PUT(p+1, 2*8);		p += 3;		U64PUT(p, dir->qidoffset, t32);		U64PUT(p+8, dir->qidmax, t32);		p += 16;	}		if(dir->gen && version < 9) {		U8PUT(p, DirGenEntry);		U16PUT(p+1, 4);		p += 3;		U32PUT(p, dir->gen);		p += 4;	}

Lines 1–500 of 745.