xref: /plan9/sys/src/cmd/fossil/vac.c (revision 6042bf6d66dcc60b2e35639f4cefa24e2aa2ecb8)
15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier 
35e96a66cSDavid du Colombier typedef struct MetaChunk MetaChunk;
45e96a66cSDavid du Colombier 
55e96a66cSDavid du Colombier struct MetaChunk {
65e96a66cSDavid du Colombier 	ushort offset;
75e96a66cSDavid du Colombier 	ushort size;
85e96a66cSDavid du Colombier 	ushort index;
95e96a66cSDavid du Colombier };
105e96a66cSDavid du Colombier 
115e96a66cSDavid du Colombier static int stringUnpack(char **s, uchar **p, int *n);
125e96a66cSDavid du Colombier static int meCmp(MetaEntry*, char *s);
135e96a66cSDavid du Colombier static int meCmpOld(MetaEntry*, char *s);
145e96a66cSDavid du Colombier 
155e96a66cSDavid du Colombier 
165e96a66cSDavid du Colombier 
175e96a66cSDavid du Colombier static char EBadMeta[] = "corrupted meta data";
185e96a66cSDavid du Colombier static char ENoFile[] = "file does not exist";
195e96a66cSDavid du Colombier 
205e96a66cSDavid du Colombier /*
215e96a66cSDavid du Colombier  * integer conversion routines
225e96a66cSDavid du Colombier  */
235e96a66cSDavid du Colombier #define	U8GET(p)	((p)[0])
245e96a66cSDavid du Colombier #define	U16GET(p)	(((p)[0]<<8)|(p)[1])
255e96a66cSDavid du Colombier #define	U32GET(p)	(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
265e96a66cSDavid du Colombier #define	U48GET(p)	(((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
275e96a66cSDavid du Colombier #define	U64GET(p)	(((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
285e96a66cSDavid du Colombier 
295e96a66cSDavid du Colombier #define	U8PUT(p,v)	(p)[0]=(v)
305e96a66cSDavid du Colombier #define	U16PUT(p,v)	(p)[0]=(v)>>8;(p)[1]=(v)
315e96a66cSDavid du Colombier #define	U32PUT(p,v)	(p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v)
325e96a66cSDavid du Colombier #define	U48PUT(p,v,t32)	t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
335e96a66cSDavid du Colombier #define	U64PUT(p,v,t32)	t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
345e96a66cSDavid du Colombier 
355e96a66cSDavid du Colombier static int
stringUnpack(char ** s,uchar ** p,int * n)365e96a66cSDavid du Colombier stringUnpack(char **s, uchar **p, int *n)
375e96a66cSDavid du Colombier {
385e96a66cSDavid du Colombier 	int nn;
395e96a66cSDavid du Colombier 
405e96a66cSDavid du Colombier 	if(*n < 2)
415e96a66cSDavid du Colombier 		return 0;
425e96a66cSDavid du Colombier 
435e96a66cSDavid du Colombier 	nn = U16GET(*p);
445e96a66cSDavid du Colombier 	*p += 2;
455e96a66cSDavid du Colombier 	*n -= 2;
465e96a66cSDavid du Colombier 	if(nn > *n)
475e96a66cSDavid du Colombier 		return 0;
485e96a66cSDavid du Colombier 	*s = vtMemAlloc(nn+1);
495e96a66cSDavid du Colombier 	memmove(*s, *p, nn);
505e96a66cSDavid du Colombier 	(*s)[nn] = 0;
515e96a66cSDavid du Colombier 	*p += nn;
525e96a66cSDavid du Colombier 	*n -= nn;
535e96a66cSDavid du Colombier 	return 1;
545e96a66cSDavid du Colombier }
555e96a66cSDavid du Colombier 
565e96a66cSDavid du Colombier static int
stringPack(char * s,uchar * p)575e96a66cSDavid du Colombier stringPack(char *s, uchar *p)
585e96a66cSDavid du Colombier {
595e96a66cSDavid du Colombier 	int n;
605e96a66cSDavid du Colombier 
615e96a66cSDavid du Colombier 	n = strlen(s);
625e96a66cSDavid du Colombier 	U16PUT(p, n);
635e96a66cSDavid du Colombier 	memmove(p+2, s, n);
645e96a66cSDavid du Colombier 	return n+2;
655e96a66cSDavid du Colombier }
665e96a66cSDavid du Colombier 
675e96a66cSDavid du Colombier int
mbSearch(MetaBlock * mb,char * elem,int * ri,MetaEntry * me)685e96a66cSDavid du Colombier mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
695e96a66cSDavid du Colombier {
705e96a66cSDavid du Colombier 	int i;
715e96a66cSDavid du Colombier 	int b, t, x;
725e96a66cSDavid du Colombier if(0)fprint(2, "mbSearch %s\n", elem);
735e96a66cSDavid du Colombier 
745e96a66cSDavid du Colombier 	/* binary search within block */
755e96a66cSDavid du Colombier 	b = 0;
765e96a66cSDavid du Colombier 	t = mb->nindex;
775e96a66cSDavid du Colombier 	while(b < t){
785e96a66cSDavid du Colombier 		i = (b+t)>>1;
795e96a66cSDavid du Colombier 		meUnpack(me, mb, i);
805e96a66cSDavid du Colombier 
815e96a66cSDavid du Colombier 		if(mb->botch)
825e96a66cSDavid du Colombier 			x = meCmpOld(me, elem);
835e96a66cSDavid du Colombier 		else
845e96a66cSDavid du Colombier 			x = meCmp(me, elem);
855e96a66cSDavid du Colombier 
865e96a66cSDavid du Colombier 		if(x == 0){
875e96a66cSDavid du Colombier 			*ri = i;
885e96a66cSDavid du Colombier 			return 1;
895e96a66cSDavid du Colombier 		}
905e96a66cSDavid du Colombier 
915e96a66cSDavid du Colombier 		if(x < 0)
925e96a66cSDavid du Colombier 			b = i+1;
935e96a66cSDavid du Colombier 		else /* x > 0 */
945e96a66cSDavid du Colombier 			t = i;
955e96a66cSDavid du Colombier 	}
965e96a66cSDavid du Colombier 
975e96a66cSDavid du Colombier 	assert(b == t);
985e96a66cSDavid du Colombier 
995e96a66cSDavid du Colombier 	*ri = b;	/* b is the index to insert this entry */
1005e96a66cSDavid du Colombier 	memset(me, 0, sizeof(*me));
1015e96a66cSDavid du Colombier 
1025e96a66cSDavid du Colombier 	vtSetError(ENoFile);
1035e96a66cSDavid du Colombier 	return 0;
1045e96a66cSDavid du Colombier }
1055e96a66cSDavid du Colombier 
1065e96a66cSDavid du Colombier void
mbInit(MetaBlock * mb,uchar * p,int n,int ne)1075e96a66cSDavid du Colombier mbInit(MetaBlock *mb, uchar *p, int n, int ne)
1085e96a66cSDavid du Colombier {
1095e96a66cSDavid du Colombier 	memset(p, 0, n);
1105e96a66cSDavid du Colombier 	mb->maxsize = n;
1115e96a66cSDavid du Colombier 	mb->maxindex = ne;
1125e96a66cSDavid du Colombier 	mb->nindex = 0;
1135e96a66cSDavid du Colombier 	mb->free = 0;
1145e96a66cSDavid du Colombier 	mb->size = MetaHeaderSize + ne*MetaIndexSize;
1155e96a66cSDavid du Colombier 	mb->buf = p;
1165e96a66cSDavid du Colombier 	mb->botch = 0;
1175e96a66cSDavid du Colombier }
1185e96a66cSDavid du Colombier 
1195e96a66cSDavid du Colombier int
mbUnpack(MetaBlock * mb,uchar * p,int n)1205e96a66cSDavid du Colombier mbUnpack(MetaBlock *mb, uchar *p, int n)
1215e96a66cSDavid du Colombier {
1225e96a66cSDavid du Colombier 	u32int magic;
1235e96a66cSDavid du Colombier 	int i;
1245e96a66cSDavid du Colombier 	int eo, en, omin;
1255e96a66cSDavid du Colombier 	uchar *q;
1265e96a66cSDavid du Colombier 
1275e96a66cSDavid du Colombier 	mb->maxsize = n;
1285e96a66cSDavid du Colombier 	mb->buf = p;
1295e96a66cSDavid du Colombier 
1305e96a66cSDavid du Colombier 	if(n == 0){
1315e96a66cSDavid du Colombier 		memset(mb, 0, sizeof(MetaBlock));
1325e96a66cSDavid du Colombier 		return 1;
1335e96a66cSDavid du Colombier 	}
1345e96a66cSDavid du Colombier 
1355e96a66cSDavid du Colombier 	magic = U32GET(p);
1365e96a66cSDavid du Colombier 	if(magic != MetaMagic && magic != MetaMagic-1)
1375e96a66cSDavid du Colombier 		goto Err;
1385e96a66cSDavid du Colombier 	mb->size = U16GET(p+4);
1395e96a66cSDavid du Colombier 	mb->free = U16GET(p+6);
1405e96a66cSDavid du Colombier 	mb->maxindex = U16GET(p+8);
1415e96a66cSDavid du Colombier 	mb->nindex = U16GET(p+10);
1425e96a66cSDavid du Colombier 	mb->botch = magic != MetaMagic;
1435e96a66cSDavid du Colombier 	if(mb->size > n)
1445e96a66cSDavid du Colombier 		goto Err;
1455e96a66cSDavid du Colombier 
1465e96a66cSDavid du Colombier 	omin = MetaHeaderSize + mb->maxindex*MetaIndexSize;
1475e96a66cSDavid du Colombier 	if(n < omin)
1485e96a66cSDavid du Colombier 		goto Err;
1495e96a66cSDavid du Colombier 
1505e96a66cSDavid du Colombier 
1515e96a66cSDavid du Colombier 	p += MetaHeaderSize;
1525e96a66cSDavid du Colombier 
1535e96a66cSDavid du Colombier 	/* check the index table - ensures that meUnpack and meCmp never fail */
1545e96a66cSDavid du Colombier 	for(i=0; i<mb->nindex; i++){
1555e96a66cSDavid du Colombier 		eo = U16GET(p);
1565e96a66cSDavid du Colombier 		en = U16GET(p+2);
1575e96a66cSDavid du Colombier 		if(eo < omin || eo+en > mb->size || en < 8)
1585e96a66cSDavid du Colombier 			goto Err;
1595e96a66cSDavid du Colombier 		q = mb->buf + eo;
1605e96a66cSDavid du Colombier 		if(U32GET(q) != DirMagic)
1615e96a66cSDavid du Colombier 			goto Err;
1625e96a66cSDavid du Colombier 		p += 4;
1635e96a66cSDavid du Colombier 	}
1645e96a66cSDavid du Colombier 
1655e96a66cSDavid du Colombier 	return 1;
1665e96a66cSDavid du Colombier Err:
1675e96a66cSDavid du Colombier 	vtSetError(EBadMeta);
1685e96a66cSDavid du Colombier 	return 0;
1695e96a66cSDavid du Colombier }
1705e96a66cSDavid du Colombier 
1715e96a66cSDavid du Colombier 
1725e96a66cSDavid du Colombier void
mbPack(MetaBlock * mb)1735e96a66cSDavid du Colombier mbPack(MetaBlock *mb)
1745e96a66cSDavid du Colombier {
1755e96a66cSDavid du Colombier 	uchar *p;
1765e96a66cSDavid du Colombier 
1775e96a66cSDavid du Colombier 	p = mb->buf;
1785e96a66cSDavid du Colombier 
1795e96a66cSDavid du Colombier 	assert(!mb->botch);
1805e96a66cSDavid du Colombier 
1815e96a66cSDavid du Colombier 	U32PUT(p, MetaMagic);
1825e96a66cSDavid du Colombier 	U16PUT(p+4, mb->size);
1835e96a66cSDavid du Colombier 	U16PUT(p+6, mb->free);
1845e96a66cSDavid du Colombier 	U16PUT(p+8, mb->maxindex);
1855e96a66cSDavid du Colombier 	U16PUT(p+10, mb->nindex);
1865e96a66cSDavid du Colombier }
1875e96a66cSDavid du Colombier 
1885e96a66cSDavid du Colombier 
1895e96a66cSDavid du Colombier void
mbDelete(MetaBlock * mb,int i)1905e96a66cSDavid du Colombier mbDelete(MetaBlock *mb, int i)
1915e96a66cSDavid du Colombier {
1925e96a66cSDavid du Colombier 	uchar *p;
1935e96a66cSDavid du Colombier 	int n;
1945e96a66cSDavid du Colombier 	MetaEntry me;
1955e96a66cSDavid du Colombier 
1965e96a66cSDavid du Colombier 	assert(i < mb->nindex);
1975e96a66cSDavid du Colombier 	meUnpack(&me, mb, i);
1985e96a66cSDavid du Colombier 	memset(me.p, 0, me.size);
1995e96a66cSDavid du Colombier 
2005e96a66cSDavid du Colombier 	if(me.p - mb->buf + me.size == mb->size)
2015e96a66cSDavid du Colombier 		mb->size -= me.size;
2025e96a66cSDavid du Colombier 	else
2035e96a66cSDavid du Colombier 		mb->free += me.size;
2045e96a66cSDavid du Colombier 
2055e96a66cSDavid du Colombier 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
2065e96a66cSDavid du Colombier 	n = (mb->nindex-i-1)*MetaIndexSize;
2075e96a66cSDavid du Colombier 	memmove(p, p+MetaIndexSize, n);
2085e96a66cSDavid du Colombier 	memset(p+n, 0, MetaIndexSize);
2095e96a66cSDavid du Colombier 	mb->nindex--;
2105e96a66cSDavid du Colombier }
2115e96a66cSDavid du Colombier 
2125e96a66cSDavid du Colombier void
mbInsert(MetaBlock * mb,int i,MetaEntry * me)2135e96a66cSDavid du Colombier mbInsert(MetaBlock *mb, int i, MetaEntry *me)
2145e96a66cSDavid du Colombier {
2155e96a66cSDavid du Colombier 	uchar *p;
2165e96a66cSDavid du Colombier 	int o, n;
2175e96a66cSDavid du Colombier 
2185e96a66cSDavid du Colombier 	assert(mb->nindex < mb->maxindex);
2195e96a66cSDavid du Colombier 
2205e96a66cSDavid du Colombier 	o = me->p - mb->buf;
2215e96a66cSDavid du Colombier 	n = me->size;
2225e96a66cSDavid du Colombier 	if(o+n > mb->size){
2235e96a66cSDavid du Colombier 		mb->free -= mb->size - o;
2245e96a66cSDavid du Colombier 		mb->size = o + n;
2255e96a66cSDavid du Colombier 	}else
2265e96a66cSDavid du Colombier 		mb->free -= n;
2275e96a66cSDavid du Colombier 
2285e96a66cSDavid du Colombier 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
2295e96a66cSDavid du Colombier 	n = (mb->nindex-i)*MetaIndexSize;
2305e96a66cSDavid du Colombier 	memmove(p+MetaIndexSize, p, n);
2315e96a66cSDavid du Colombier 	U16PUT(p, me->p - mb->buf);
2325e96a66cSDavid du Colombier 	U16PUT(p+2, me->size);
2335e96a66cSDavid du Colombier 	mb->nindex++;
2345e96a66cSDavid du Colombier }
2355e96a66cSDavid du Colombier 
2365e96a66cSDavid du Colombier int
mbResize(MetaBlock * mb,MetaEntry * me,int n)2375e96a66cSDavid du Colombier mbResize(MetaBlock *mb, MetaEntry *me, int n)
2385e96a66cSDavid du Colombier {
2395e96a66cSDavid du Colombier 	uchar *p, *ep;
2405e96a66cSDavid du Colombier 
2415e96a66cSDavid du Colombier 	/* easy case */
2425e96a66cSDavid du Colombier 	if(n <= me->size){
2435e96a66cSDavid du Colombier 		me->size = n;
2445e96a66cSDavid du Colombier 		return 1;
2455e96a66cSDavid du Colombier 	}
2465e96a66cSDavid du Colombier 
2475e96a66cSDavid du Colombier 	/* try and expand entry */
2485e96a66cSDavid du Colombier 
2495e96a66cSDavid du Colombier 	p = me->p + me->size;
2505e96a66cSDavid du Colombier 	ep = mb->buf + mb->maxsize;
2515e96a66cSDavid du Colombier 	while(p < ep && *p == 0)
2525e96a66cSDavid du Colombier 		p++;
2535e96a66cSDavid du Colombier 	if(n <= p - me->p){
2545e96a66cSDavid du Colombier 		me->size = n;
2555e96a66cSDavid du Colombier 		return 1;
2565e96a66cSDavid du Colombier 	}
2575e96a66cSDavid du Colombier 
2585e96a66cSDavid du Colombier 	p = mbAlloc(mb, n);
2595e96a66cSDavid du Colombier 	if(p != nil){
2605e96a66cSDavid du Colombier 		me->p = p;
2615e96a66cSDavid du Colombier 		me->size = n;
2625e96a66cSDavid du Colombier 		return 1;
2635e96a66cSDavid du Colombier 	}
2645e96a66cSDavid du Colombier 
2655e96a66cSDavid du Colombier 	return 0;
2665e96a66cSDavid du Colombier }
2675e96a66cSDavid du Colombier 
2685e96a66cSDavid du Colombier void
meUnpack(MetaEntry * me,MetaBlock * mb,int i)2695e96a66cSDavid du Colombier meUnpack(MetaEntry *me, MetaBlock *mb, int i)
2705e96a66cSDavid du Colombier {
2715e96a66cSDavid du Colombier 	uchar *p;
2725e96a66cSDavid du Colombier 	int eo, en;
2735e96a66cSDavid du Colombier 
2745e96a66cSDavid du Colombier 	assert(i >= 0 && i < mb->nindex);
2755e96a66cSDavid du Colombier 
2765e96a66cSDavid du Colombier 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
2775e96a66cSDavid du Colombier 	eo = U16GET(p);
2785e96a66cSDavid du Colombier 	en = U16GET(p+2);
2795e96a66cSDavid du Colombier 
2805e96a66cSDavid du Colombier 	me->p = mb->buf + eo;
2815e96a66cSDavid du Colombier 	me->size = en;
2825e96a66cSDavid du Colombier 
2835e96a66cSDavid du Colombier 	/* checked by mbUnpack */
2845e96a66cSDavid du Colombier 	assert(me->size >= 8);
2855e96a66cSDavid du Colombier }
2865e96a66cSDavid du Colombier 
2875e96a66cSDavid du Colombier /* assumes a small amount of checking has been done in mbEntry */
2885e96a66cSDavid du Colombier static int
meCmp(MetaEntry * me,char * s)2895e96a66cSDavid du Colombier meCmp(MetaEntry *me, char *s)
2905e96a66cSDavid du Colombier {
2915e96a66cSDavid du Colombier 	int n;
2925e96a66cSDavid du Colombier 	uchar *p;
2935e96a66cSDavid du Colombier 
2945e96a66cSDavid du Colombier 	p = me->p;
2955e96a66cSDavid du Colombier 
2965e96a66cSDavid du Colombier 	/* skip magic & version */
2975e96a66cSDavid du Colombier 	p += 6;
2985e96a66cSDavid du Colombier 	n = U16GET(p);
2995e96a66cSDavid du Colombier 	p += 2;
3005e96a66cSDavid du Colombier 
3015e96a66cSDavid du Colombier 	if(n > me->size - 8)
3025e96a66cSDavid du Colombier 		n = me->size - 8;
3035e96a66cSDavid du Colombier 
3045e96a66cSDavid du Colombier 	while(n > 0){
3055e96a66cSDavid du Colombier 		if(*s == 0)
3065e96a66cSDavid du Colombier 			return 1;
3075e96a66cSDavid du Colombier 		if(*p < (uchar)*s)
3085e96a66cSDavid du Colombier 			return -1;
3095e96a66cSDavid du Colombier 		if(*p > (uchar)*s)
3105e96a66cSDavid du Colombier 			return 1;
3115e96a66cSDavid du Colombier 		p++;
3125e96a66cSDavid du Colombier 		s++;
3135e96a66cSDavid du Colombier 		n--;
3145e96a66cSDavid du Colombier 	}
3155e96a66cSDavid du Colombier 	return -(*s != 0);
3165e96a66cSDavid du Colombier }
3175e96a66cSDavid du Colombier 
3185e96a66cSDavid du Colombier /*
3195e96a66cSDavid du Colombier  * This is the old and broken meCmp.
3205e96a66cSDavid du Colombier  * This cmp routine reverse the sense of the comparison
3215e96a66cSDavid du Colombier  * when one string is a prefix of the other.
3225e96a66cSDavid du Colombier  * In other words, it put "ab" after "abc" rather
3235e96a66cSDavid du Colombier  * than before.  This behaviour is ok; binary search
3245e96a66cSDavid du Colombier  * and sort still work.  However, it is goes against
3255e96a66cSDavid du Colombier  * the usual convention.
3265e96a66cSDavid du Colombier  */
3275e96a66cSDavid du Colombier static int
meCmpOld(MetaEntry * me,char * s)3285e96a66cSDavid du Colombier meCmpOld(MetaEntry *me, char *s)
3295e96a66cSDavid du Colombier {
3305e96a66cSDavid du Colombier 	int n;
3315e96a66cSDavid du Colombier 	uchar *p;
3325e96a66cSDavid du Colombier 
3335e96a66cSDavid du Colombier 	p = me->p;
3345e96a66cSDavid du Colombier 
3355e96a66cSDavid du Colombier 	/* skip magic & version */
3365e96a66cSDavid du Colombier 	p += 6;
3375e96a66cSDavid du Colombier 	n = U16GET(p);
3385e96a66cSDavid du Colombier 	p += 2;
3395e96a66cSDavid du Colombier 
3405e96a66cSDavid du Colombier 	if(n > me->size - 8)
3415e96a66cSDavid du Colombier 		n = me->size - 8;
3425e96a66cSDavid du Colombier 
3435e96a66cSDavid du Colombier 	while(n > 0){
3445e96a66cSDavid du Colombier 		if(*s == 0)
3455e96a66cSDavid du Colombier 			return -1;
3465e96a66cSDavid du Colombier 		if(*p < (uchar)*s)
3475e96a66cSDavid du Colombier 			return -1;
3485e96a66cSDavid du Colombier 		if(*p > (uchar)*s)
3495e96a66cSDavid du Colombier 			return 1;
3505e96a66cSDavid du Colombier 		p++;
3515e96a66cSDavid du Colombier 		s++;
3525e96a66cSDavid du Colombier 		n--;
3535e96a66cSDavid du Colombier 	}
3545e96a66cSDavid du Colombier 	return *s != 0;
3555e96a66cSDavid du Colombier }
3565e96a66cSDavid du Colombier 
3575e96a66cSDavid du Colombier static int
offsetCmp(void * s0,void * s1)3585e96a66cSDavid du Colombier offsetCmp(void *s0, void *s1)
3595e96a66cSDavid du Colombier {
3605e96a66cSDavid du Colombier 	MetaChunk *mc0, *mc1;
3615e96a66cSDavid du Colombier 
3625e96a66cSDavid du Colombier 	mc0 = s0;
3635e96a66cSDavid du Colombier 	mc1 = s1;
3645e96a66cSDavid du Colombier 	if(mc0->offset < mc1->offset)
3655e96a66cSDavid du Colombier 		return -1;
3665e96a66cSDavid du Colombier 	if(mc0->offset > mc1->offset)
3675e96a66cSDavid du Colombier 		return 1;
3685e96a66cSDavid du Colombier 	return 0;
3695e96a66cSDavid du Colombier }
3705e96a66cSDavid du Colombier 
3715e96a66cSDavid du Colombier static MetaChunk *
metaChunks(MetaBlock * mb)3725e96a66cSDavid du Colombier metaChunks(MetaBlock *mb)
3735e96a66cSDavid du Colombier {
3745e96a66cSDavid du Colombier 	MetaChunk *mc;
3755e96a66cSDavid du Colombier 	int oo, o, n, i;
3765e96a66cSDavid du Colombier 	uchar *p;
3775e96a66cSDavid du Colombier 
3785e96a66cSDavid du Colombier 	mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));
3795e96a66cSDavid du Colombier 	p = mb->buf + MetaHeaderSize;
3805e96a66cSDavid du Colombier 	for(i = 0; i<mb->nindex; i++){
3815e96a66cSDavid du Colombier 		mc[i].offset = U16GET(p);
3825e96a66cSDavid du Colombier 		mc[i].size = U16GET(p+2);
3835e96a66cSDavid du Colombier 		mc[i].index = i;
3845e96a66cSDavid du Colombier 		p += MetaIndexSize;
3855e96a66cSDavid du Colombier 	}
3865e96a66cSDavid du Colombier 
3875e96a66cSDavid du Colombier 	qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
3885e96a66cSDavid du Colombier 
3895e96a66cSDavid du Colombier 	/* check block looks ok */
3905e96a66cSDavid du Colombier 	oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
3915e96a66cSDavid du Colombier 	o = oo;
3925e96a66cSDavid du Colombier 	n = 0;
3935e96a66cSDavid du Colombier 	for(i=0; i<mb->nindex; i++){
3945e96a66cSDavid du Colombier 		o = mc[i].offset;
3955e96a66cSDavid du Colombier 		n = mc[i].size;
3965e96a66cSDavid du Colombier 		if(o < oo)
3975e96a66cSDavid du Colombier 			goto Err;
3985e96a66cSDavid du Colombier 		oo += n;
3995e96a66cSDavid du Colombier 	}
4005e96a66cSDavid du Colombier 	if(o+n > mb->size)
4015e96a66cSDavid du Colombier 		goto Err;
4025e96a66cSDavid du Colombier 	if(mb->size - oo != mb->free)
4035e96a66cSDavid du Colombier 		goto Err;
4045e96a66cSDavid du Colombier 
4055e96a66cSDavid du Colombier 	return mc;
4065e96a66cSDavid du Colombier Err:
4075e96a66cSDavid du Colombier fprint(2, "metaChunks failed!\n");
4085e96a66cSDavid du Colombier oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
4095e96a66cSDavid du Colombier for(i=0; i<mb->nindex; i++){
4105e96a66cSDavid du Colombier fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size);
4115e96a66cSDavid du Colombier oo += mc[i].size;
4125e96a66cSDavid du Colombier }
4135e96a66cSDavid du Colombier fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo);
4145e96a66cSDavid du Colombier 	vtSetError(EBadMeta);
4155e96a66cSDavid du Colombier 	vtMemFree(mc);
4165e96a66cSDavid du Colombier 	return nil;
4175e96a66cSDavid du Colombier }
4185e96a66cSDavid du Colombier 
4195e96a66cSDavid du Colombier static void
mbCompact(MetaBlock * mb,MetaChunk * mc)4205e96a66cSDavid du Colombier mbCompact(MetaBlock *mb, MetaChunk *mc)
4215e96a66cSDavid du Colombier {
4225e96a66cSDavid du Colombier 	int oo, o, n, i;
4235e96a66cSDavid du Colombier 
4245e96a66cSDavid du Colombier 	oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
4255e96a66cSDavid du Colombier 
4265e96a66cSDavid du Colombier 	for(i=0; i<mb->nindex; i++){
4275e96a66cSDavid du Colombier 		o = mc[i].offset;
4285e96a66cSDavid du Colombier 		n = mc[i].size;
4295e96a66cSDavid du Colombier 		if(o != oo){
4305e96a66cSDavid du Colombier 			memmove(mb->buf + oo, mb->buf + o, n);
4315e96a66cSDavid du Colombier 			U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
4325e96a66cSDavid du Colombier 		}
4335e96a66cSDavid du Colombier 		oo += n;
4345e96a66cSDavid du Colombier 	}
4355e96a66cSDavid du Colombier 
4365e96a66cSDavid du Colombier 	mb->size = oo;
4375e96a66cSDavid du Colombier 	mb->free = 0;
4385e96a66cSDavid du Colombier }
4395e96a66cSDavid du Colombier 
4405e96a66cSDavid du Colombier uchar *
mbAlloc(MetaBlock * mb,int n)4415e96a66cSDavid du Colombier mbAlloc(MetaBlock *mb, int n)
4425e96a66cSDavid du Colombier {
4435e96a66cSDavid du Colombier 	int i, o;
4445e96a66cSDavid du Colombier 	MetaChunk *mc;
4455e96a66cSDavid du Colombier 
4465e96a66cSDavid du Colombier 	/* off the end */
4475e96a66cSDavid du Colombier 	if(mb->maxsize - mb->size >= n)
4485e96a66cSDavid du Colombier 		return mb->buf + mb->size;
4495e96a66cSDavid du Colombier 
4505e96a66cSDavid du Colombier 	/* check if possible */
4515e96a66cSDavid du Colombier 	if(mb->maxsize - mb->size + mb->free < n)
4525e96a66cSDavid du Colombier 		return nil;
4535e96a66cSDavid du Colombier 
4545e96a66cSDavid du Colombier 	mc = metaChunks(mb);
4555e96a66cSDavid du Colombier 	if(mc == nil){
4565e96a66cSDavid du Colombier fprint(2, "mbAlloc: metaChunks failed: %r\n");
4575e96a66cSDavid du Colombier 		return nil;
4585e96a66cSDavid du Colombier 	}
4595e96a66cSDavid du Colombier 
4605e96a66cSDavid du Colombier 	/* look for hole */
4615e96a66cSDavid du Colombier 	o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
4625e96a66cSDavid du Colombier 	for(i=0; i<mb->nindex; i++){
4635e96a66cSDavid du Colombier 		if(mc[i].offset - o >= n){
4645e96a66cSDavid du Colombier 			vtMemFree(mc);
4655e96a66cSDavid du Colombier 			return mb->buf + o;
4665e96a66cSDavid du Colombier 		}
4675e96a66cSDavid du Colombier 		o = mc[i].offset + mc[i].size;
4685e96a66cSDavid du Colombier 	}
4695e96a66cSDavid du Colombier 
4705e96a66cSDavid du Colombier 	if(mb->maxsize - o >= n){
4715e96a66cSDavid du Colombier 		vtMemFree(mc);
4725e96a66cSDavid du Colombier 		return mb->buf + o;
4735e96a66cSDavid du Colombier 	}
4745e96a66cSDavid du Colombier 
4755e96a66cSDavid du Colombier 	/* compact and return off the end */
4765e96a66cSDavid du Colombier 	mbCompact(mb, mc);
4775e96a66cSDavid du Colombier 	vtMemFree(mc);
4785e96a66cSDavid du Colombier 
4795e96a66cSDavid du Colombier 	if(mb->maxsize - mb->size < n){
4805e96a66cSDavid du Colombier 		vtSetError(EBadMeta);
4815e96a66cSDavid du Colombier 		return nil;
4825e96a66cSDavid du Colombier 	}
4835e96a66cSDavid du Colombier 	return mb->buf + mb->size;
4845e96a66cSDavid du Colombier }
4855e96a66cSDavid du Colombier 
4865e96a66cSDavid du Colombier int
deSize(DirEntry * dir)4875e96a66cSDavid du Colombier deSize(DirEntry *dir)
4885e96a66cSDavid du Colombier {
4895e96a66cSDavid du Colombier 	int n;
4905e96a66cSDavid du Colombier 
4915e96a66cSDavid du Colombier 	/* constant part */
4925e96a66cSDavid du Colombier 
4935e96a66cSDavid du Colombier 	n = 	4 +	/* magic */
4945e96a66cSDavid du Colombier 		2 + 	/* version */
4955e96a66cSDavid du Colombier 		4 +	/* entry */
4965e96a66cSDavid du Colombier 		4 + 	/* guid */
4975e96a66cSDavid du Colombier 		4 + 	/* mentry */
4985e96a66cSDavid du Colombier 		4 + 	/* mgen */
4995e96a66cSDavid du Colombier 		8 +	/* qid */
5005e96a66cSDavid du Colombier 		4 + 	/* mtime */
5015e96a66cSDavid du Colombier 		4 + 	/* mcount */
5025e96a66cSDavid du Colombier 		4 + 	/* ctime */
5035e96a66cSDavid du Colombier 		4 + 	/* atime */
5045e96a66cSDavid du Colombier 		4 +	/* mode */
5055e96a66cSDavid du Colombier 		0;
5065e96a66cSDavid du Colombier 
5075e96a66cSDavid du Colombier 	/* strings */
5085e96a66cSDavid du Colombier 	n += 2 + strlen(dir->elem);
5095e96a66cSDavid du Colombier 	n += 2 + strlen(dir->uid);
5105e96a66cSDavid du Colombier 	n += 2 + strlen(dir->gid);
5115e96a66cSDavid du Colombier 	n += 2 + strlen(dir->mid);
5125e96a66cSDavid du Colombier 
5135e96a66cSDavid du Colombier 	/* optional sections */
5145e96a66cSDavid du Colombier 	if(dir->qidSpace){
5155e96a66cSDavid du Colombier 		n += 	3 + 	/* option header */
5165e96a66cSDavid du Colombier 			8 + 	/* qidOffset */
5175e96a66cSDavid du Colombier 			8;	/* qid Max */
5185e96a66cSDavid du Colombier 	}
5195e96a66cSDavid du Colombier 
5205e96a66cSDavid du Colombier 	return n;
5215e96a66cSDavid du Colombier }
5225e96a66cSDavid du Colombier 
5235e96a66cSDavid du Colombier void
dePack(DirEntry * dir,MetaEntry * me)5245e96a66cSDavid du Colombier dePack(DirEntry *dir, MetaEntry *me)
5255e96a66cSDavid du Colombier {
5265e96a66cSDavid du Colombier 	uchar *p;
5275e96a66cSDavid du Colombier 	ulong t32;
5285e96a66cSDavid du Colombier 
5295e96a66cSDavid du Colombier 	p = me->p;
5305e96a66cSDavid du Colombier 
5315e96a66cSDavid du Colombier 	U32PUT(p, DirMagic);
5325e96a66cSDavid du Colombier 	U16PUT(p+4, 9);		/* version */
5335e96a66cSDavid du Colombier 	p += 6;
5345e96a66cSDavid du Colombier 
5355e96a66cSDavid du Colombier 	p += stringPack(dir->elem, p);
5365e96a66cSDavid du Colombier 
5375e96a66cSDavid du Colombier 	U32PUT(p, dir->entry);
5385e96a66cSDavid du Colombier 	U32PUT(p+4, dir->gen);
5395e96a66cSDavid du Colombier 	U32PUT(p+8, dir->mentry);
5405e96a66cSDavid du Colombier 	U32PUT(p+12, dir->mgen);
5415e96a66cSDavid du Colombier 	U64PUT(p+16, dir->qid, t32);
5425e96a66cSDavid du Colombier 	p += 24;
5435e96a66cSDavid du Colombier 
5445e96a66cSDavid du Colombier 	p += stringPack(dir->uid, p);
5455e96a66cSDavid du Colombier 	p += stringPack(dir->gid, p);
5465e96a66cSDavid du Colombier 	p += stringPack(dir->mid, p);
5475e96a66cSDavid du Colombier 
5485e96a66cSDavid du Colombier 	U32PUT(p, dir->mtime);
5495e96a66cSDavid du Colombier 	U32PUT(p+4, dir->mcount);
5505e96a66cSDavid du Colombier 	U32PUT(p+8, dir->ctime);
5515e96a66cSDavid du Colombier 	U32PUT(p+12, dir->atime);
5525e96a66cSDavid du Colombier 	U32PUT(p+16, dir->mode);
5535e96a66cSDavid du Colombier 	p += 5*4;
5545e96a66cSDavid du Colombier 
5555e96a66cSDavid du Colombier 	if(dir->qidSpace){
5565e96a66cSDavid du Colombier 		U8PUT(p, DeQidSpace);
5575e96a66cSDavid du Colombier 		U16PUT(p+1, 2*8);
5585e96a66cSDavid du Colombier 		p += 3;
5595e96a66cSDavid du Colombier 		U64PUT(p, dir->qidOffset, t32);
5605e96a66cSDavid du Colombier 		U64PUT(p+8, dir->qidMax, t32);
5615e96a66cSDavid du Colombier 		p += 16;
5625e96a66cSDavid du Colombier 	}
5635e96a66cSDavid du Colombier 
5645e96a66cSDavid du Colombier 	assert(p == me->p + me->size);
5655e96a66cSDavid du Colombier }
5665e96a66cSDavid du Colombier 
5675e96a66cSDavid du Colombier 
5685e96a66cSDavid du Colombier int
deUnpack(DirEntry * dir,MetaEntry * me)5695e96a66cSDavid du Colombier deUnpack(DirEntry *dir, MetaEntry *me)
5705e96a66cSDavid du Colombier {
5715e96a66cSDavid du Colombier 	int t, nn, n, version;
5725e96a66cSDavid du Colombier 	uchar *p;
5735e96a66cSDavid du Colombier 
5745e96a66cSDavid du Colombier 	p = me->p;
5755e96a66cSDavid du Colombier 	n = me->size;
5765e96a66cSDavid du Colombier 
5775e96a66cSDavid du Colombier 	memset(dir, 0, sizeof(DirEntry));
5785e96a66cSDavid du Colombier 
579*6042bf6dSDavid du Colombier if(0)print("deUnpack\n");
5805e96a66cSDavid du Colombier 	/* magic */
5815e96a66cSDavid du Colombier 	if(n < 4 || U32GET(p) != DirMagic)
5825e96a66cSDavid du Colombier 		goto Err;
5835e96a66cSDavid du Colombier 	p += 4;
5845e96a66cSDavid du Colombier 	n -= 4;
5855e96a66cSDavid du Colombier 
586*6042bf6dSDavid du Colombier if(0)print("deUnpack: got magic\n");
5875e96a66cSDavid du Colombier 	/* version */
5885e96a66cSDavid du Colombier 	if(n < 2)
5895e96a66cSDavid du Colombier 		goto Err;
5905e96a66cSDavid du Colombier 	version = U16GET(p);
5915e96a66cSDavid du Colombier 	if(version < 7 || version > 9)
5925e96a66cSDavid du Colombier 		goto Err;
5935e96a66cSDavid du Colombier 	p += 2;
5945e96a66cSDavid du Colombier 	n -= 2;
5955e96a66cSDavid du Colombier 
596*6042bf6dSDavid du Colombier if(0)print("deUnpack: got version\n");
5975e96a66cSDavid du Colombier 
5985e96a66cSDavid du Colombier 	/* elem */
5995e96a66cSDavid du Colombier 	if(!stringUnpack(&dir->elem, &p, &n))
6005e96a66cSDavid du Colombier 		goto Err;
6015e96a66cSDavid du Colombier 
602*6042bf6dSDavid du Colombier if(0)print("deUnpack: got elem\n");
6035e96a66cSDavid du Colombier 
6045e96a66cSDavid du Colombier 	/* entry  */
6055e96a66cSDavid du Colombier 	if(n < 4)
6065e96a66cSDavid du Colombier 		goto Err;
6075e96a66cSDavid du Colombier 	dir->entry = U32GET(p);
6085e96a66cSDavid du Colombier 	p += 4;
6095e96a66cSDavid du Colombier 	n -= 4;
6105e96a66cSDavid du Colombier 
611*6042bf6dSDavid du Colombier if(0)print("deUnpack: got entry\n");
6125e96a66cSDavid du Colombier 
6135e96a66cSDavid du Colombier 	if(version < 9){
6145e96a66cSDavid du Colombier 		dir->gen = 0;
6155e96a66cSDavid du Colombier 		dir->mentry = dir->entry+1;
6165e96a66cSDavid du Colombier 		dir->mgen = 0;
6175e96a66cSDavid du Colombier 	}else{
6185e96a66cSDavid du Colombier 		if(n < 3*4)
6195e96a66cSDavid du Colombier 			goto Err;
6205e96a66cSDavid du Colombier 		dir->gen = U32GET(p);
6215e96a66cSDavid du Colombier 		dir->mentry = U32GET(p+4);
6225e96a66cSDavid du Colombier 		dir->mgen = U32GET(p+8);
6235e96a66cSDavid du Colombier 		p += 3*4;
6245e96a66cSDavid du Colombier 		n -= 3*4;
6255e96a66cSDavid du Colombier 	}
6265e96a66cSDavid du Colombier 
627*6042bf6dSDavid du Colombier if(0)print("deUnpack: got gen etc\n");
6285e96a66cSDavid du Colombier 
6295e96a66cSDavid du Colombier 	/* size is gotten from VtEntry */
6305e96a66cSDavid du Colombier 	dir->size = 0;
6315e96a66cSDavid du Colombier 
6325e96a66cSDavid du Colombier 	/* qid */
6335e96a66cSDavid du Colombier 	if(n < 8)
6345e96a66cSDavid du Colombier 		goto Err;
6355e96a66cSDavid du Colombier 	dir->qid = U64GET(p);
6365e96a66cSDavid du Colombier 	p += 8;
6375e96a66cSDavid du Colombier 	n -= 8;
6385e96a66cSDavid du Colombier 
639*6042bf6dSDavid du Colombier if(0)print("deUnpack: got qid\n");
6405e96a66cSDavid du Colombier 	/* skip replacement */
6415e96a66cSDavid du Colombier 	if(version == 7){
6425e96a66cSDavid du Colombier 		if(n < VtScoreSize)
6435e96a66cSDavid du Colombier 			goto Err;
6445e96a66cSDavid du Colombier 		p += VtScoreSize;
6455e96a66cSDavid du Colombier 		n -= VtScoreSize;
6465e96a66cSDavid du Colombier 	}
6475e96a66cSDavid du Colombier 
6485e96a66cSDavid du Colombier 	/* uid */
6495e96a66cSDavid du Colombier 	if(!stringUnpack(&dir->uid, &p, &n))
6505e96a66cSDavid du Colombier 		goto Err;
6515e96a66cSDavid du Colombier 
6525e96a66cSDavid du Colombier 	/* gid */
6535e96a66cSDavid du Colombier 	if(!stringUnpack(&dir->gid, &p, &n))
6545e96a66cSDavid du Colombier 		goto Err;
6555e96a66cSDavid du Colombier 
6565e96a66cSDavid du Colombier 	/* mid */
6575e96a66cSDavid du Colombier 	if(!stringUnpack(&dir->mid, &p, &n))
6585e96a66cSDavid du Colombier 		goto Err;
6595e96a66cSDavid du Colombier 
660*6042bf6dSDavid du Colombier if(0)print("deUnpack: got ids\n");
6615e96a66cSDavid du Colombier 	if(n < 5*4)
6625e96a66cSDavid du Colombier 		goto Err;
6635e96a66cSDavid du Colombier 	dir->mtime = U32GET(p);
6645e96a66cSDavid du Colombier 	dir->mcount = U32GET(p+4);
6655e96a66cSDavid du Colombier 	dir->ctime = U32GET(p+8);
6665e96a66cSDavid du Colombier 	dir->atime = U32GET(p+12);
6675e96a66cSDavid du Colombier 	dir->mode = U32GET(p+16);
6685e96a66cSDavid du Colombier 	p += 5*4;
6695e96a66cSDavid du Colombier 	n -= 5*4;
6705e96a66cSDavid du Colombier 
671*6042bf6dSDavid du Colombier if(0)print("deUnpack: got times\n");
6725e96a66cSDavid du Colombier 	/* optional meta data */
6735e96a66cSDavid du Colombier 	while(n > 0){
6745e96a66cSDavid du Colombier 		if(n < 3)
6755e96a66cSDavid du Colombier 			goto Err;
6765e96a66cSDavid du Colombier 		t = p[0];
6775e96a66cSDavid du Colombier 		nn = U16GET(p+1);
6785e96a66cSDavid du Colombier 		p += 3;
6795e96a66cSDavid du Colombier 		n -= 3;
6805e96a66cSDavid du Colombier 		if(n < nn)
6815e96a66cSDavid du Colombier 			goto Err;
6825e96a66cSDavid du Colombier 		switch(t){
6835e96a66cSDavid du Colombier 		case DePlan9:
6845e96a66cSDavid du Colombier 			/* not valid in version >= 9 */
6855e96a66cSDavid du Colombier 			if(version >= 9)
6865e96a66cSDavid du Colombier 				break;
6875e96a66cSDavid du Colombier 			if(dir->plan9 || nn != 12)
6885e96a66cSDavid du Colombier 				goto Err;
6895e96a66cSDavid du Colombier 			dir->plan9 = 1;
6905e96a66cSDavid du Colombier 			dir->p9path = U64GET(p);
6915e96a66cSDavid du Colombier 			dir->p9version = U32GET(p+8);
6925e96a66cSDavid du Colombier 			if(dir->mcount == 0)
6935e96a66cSDavid du Colombier 				dir->mcount = dir->p9version;
6945e96a66cSDavid du Colombier 			break;
6955e96a66cSDavid du Colombier 		case DeGen:
6965e96a66cSDavid du Colombier 			/* not valid in version >= 9 */
6975e96a66cSDavid du Colombier 			if(version >= 9)
6985e96a66cSDavid du Colombier 				break;
6995e96a66cSDavid du Colombier 			break;
7005e96a66cSDavid du Colombier 		case DeQidSpace:
7015e96a66cSDavid du Colombier 			if(dir->qidSpace || nn != 16)
7025e96a66cSDavid du Colombier 				goto Err;
7035e96a66cSDavid du Colombier 			dir->qidSpace = 1;
7045e96a66cSDavid du Colombier 			dir->qidOffset = U64GET(p);
7055e96a66cSDavid du Colombier 			dir->qidMax = U64GET(p+8);
7065e96a66cSDavid du Colombier 			break;
7075e96a66cSDavid du Colombier 		}
7085e96a66cSDavid du Colombier 		p += nn;
7095e96a66cSDavid du Colombier 		n -= nn;
7105e96a66cSDavid du Colombier 	}
711*6042bf6dSDavid du Colombier if(0)print("deUnpack: got options\n");
7125e96a66cSDavid du Colombier 
7135e96a66cSDavid du Colombier 	if(p != me->p + me->size)
7145e96a66cSDavid du Colombier 		goto Err;
7155e96a66cSDavid du Colombier 
716*6042bf6dSDavid du Colombier if(0)print("deUnpack: correct size\n");
7175e96a66cSDavid du Colombier 	return 1;
7185e96a66cSDavid du Colombier Err:
719*6042bf6dSDavid du Colombier if(0)print("deUnpack: XXXXXXXXXXXX EBadMeta\n");
7205e96a66cSDavid du Colombier 	vtSetError(EBadMeta);
7215e96a66cSDavid du Colombier 	deCleanup(dir);
7225e96a66cSDavid du Colombier 	return 0;
7235e96a66cSDavid du Colombier }
7245e96a66cSDavid du Colombier 
7255e96a66cSDavid du Colombier void
deCleanup(DirEntry * dir)7265e96a66cSDavid du Colombier deCleanup(DirEntry *dir)
7275e96a66cSDavid du Colombier {
7285e96a66cSDavid du Colombier 	vtMemFree(dir->elem);
7295e96a66cSDavid du Colombier 	dir->elem = nil;
7305e96a66cSDavid du Colombier 	vtMemFree(dir->uid);
7315e96a66cSDavid du Colombier 	dir->uid = nil;
7325e96a66cSDavid du Colombier 	vtMemFree(dir->gid);
7335e96a66cSDavid du Colombier 	dir->gid = nil;
7345e96a66cSDavid du Colombier 	vtMemFree(dir->mid);
7355e96a66cSDavid du Colombier 	dir->mid = nil;
7365e96a66cSDavid du Colombier }
7375e96a66cSDavid du Colombier 
7385e96a66cSDavid du Colombier void
deCopy(DirEntry * dst,DirEntry * src)7395e96a66cSDavid du Colombier deCopy(DirEntry *dst, DirEntry *src)
7405e96a66cSDavid du Colombier {
7415e96a66cSDavid du Colombier 	*dst = *src;
7425e96a66cSDavid du Colombier 	dst->elem = vtStrDup(src->elem);
7435e96a66cSDavid du Colombier 	dst->uid = vtStrDup(src->uid);
7445e96a66cSDavid du Colombier 	dst->gid = vtStrDup(src->gid);
7455e96a66cSDavid du Colombier 	dst->mid = vtStrDup(src->mid);
7465e96a66cSDavid du Colombier }
747