xref: /plan9/sys/src/cmd/vac/pack.c (revision 3be74836e45a818042257560f5093e4f51d57220)
1d9306527SDavid du Colombier #include "stdinc.h"
2d9306527SDavid du Colombier #include "vac.h"
3d9306527SDavid du Colombier #include "dat.h"
4d9306527SDavid du Colombier #include "fns.h"
5d9306527SDavid du Colombier #include "error.h"
6d9306527SDavid du Colombier 
7d9306527SDavid du Colombier typedef struct MetaChunk MetaChunk;
8d9306527SDavid du Colombier 
9d9306527SDavid du Colombier struct MetaChunk {
10d9306527SDavid du Colombier 	ushort offset;
11d9306527SDavid du Colombier 	ushort size;
12d9306527SDavid du Colombier 	ushort index;
13d9306527SDavid du Colombier };
14d9306527SDavid du Colombier 
15*3be74836SDavid du Colombier static int	stringunpack(char **s, uchar **p, int *n);
16d9306527SDavid du Colombier 
17d9306527SDavid du Colombier /*
18d9306527SDavid du Colombier  * integer conversion routines
19d9306527SDavid du Colombier  */
20d9306527SDavid du Colombier #define	U8GET(p)	((p)[0])
21d9306527SDavid du Colombier #define	U16GET(p)	(((p)[0]<<8)|(p)[1])
22d9306527SDavid du Colombier #define	U32GET(p)	(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
23d9306527SDavid du Colombier #define	U48GET(p)	(((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
24d9306527SDavid du Colombier #define	U64GET(p)	(((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
25d9306527SDavid du Colombier 
26*3be74836SDavid du Colombier #define	U8PUT(p,v)	(p)[0]=(v)&0xFF
27*3be74836SDavid du Colombier #define	U16PUT(p,v)	(p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF
28*3be74836SDavid du Colombier #define	U32PUT(p,v)	(p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF
29d9306527SDavid du Colombier #define	U48PUT(p,v,t32)	t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
30d9306527SDavid du Colombier #define	U64PUT(p,v,t32)	t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
31d9306527SDavid du Colombier 
32d9306527SDavid du Colombier static int
stringunpack(char ** s,uchar ** p,int * n)33*3be74836SDavid du Colombier stringunpack(char **s, uchar **p, int *n)
34d9306527SDavid du Colombier {
35d9306527SDavid du Colombier 	int nn;
36d9306527SDavid du Colombier 
37d9306527SDavid du Colombier 	if(*n < 2)
38*3be74836SDavid du Colombier 		return -1;
39d9306527SDavid du Colombier 
40d9306527SDavid du Colombier 	nn = U16GET(*p);
41d9306527SDavid du Colombier 	*p += 2;
42d9306527SDavid du Colombier 	*n -= 2;
43d9306527SDavid du Colombier 	if(nn > *n)
44*3be74836SDavid du Colombier 		return -1;
45*3be74836SDavid du Colombier 	*s = vtmalloc(nn+1);
46d9306527SDavid du Colombier 	memmove(*s, *p, nn);
47d9306527SDavid du Colombier 	(*s)[nn] = 0;
48d9306527SDavid du Colombier 	*p += nn;
49d9306527SDavid du Colombier 	*n -= nn;
50*3be74836SDavid du Colombier 	return 0;
51d9306527SDavid du Colombier }
52d9306527SDavid du Colombier 
53d9306527SDavid du Colombier static int
stringpack(char * s,uchar * p)54*3be74836SDavid du Colombier stringpack(char *s, uchar *p)
55d9306527SDavid du Colombier {
56d9306527SDavid du Colombier 	int n;
57d9306527SDavid du Colombier 
58d9306527SDavid du Colombier 	n = strlen(s);
59d9306527SDavid du Colombier 	U16PUT(p, n);
60d9306527SDavid du Colombier 	memmove(p+2, s, n);
61d9306527SDavid du Colombier 	return n+2;
62d9306527SDavid du Colombier }
63d9306527SDavid du Colombier 
64d9306527SDavid du Colombier 
65d9306527SDavid du Colombier int
mbunpack(MetaBlock * mb,uchar * p,int n)66*3be74836SDavid du Colombier mbunpack(MetaBlock *mb, uchar *p, int n)
67d9306527SDavid du Colombier {
68d9306527SDavid du Colombier 	u32int magic;
69d9306527SDavid du Colombier 
70d9306527SDavid du Colombier 	mb->maxsize = n;
71d9306527SDavid du Colombier 	mb->buf = p;
72d9306527SDavid du Colombier 
73d9306527SDavid du Colombier 	if(n == 0) {
74d9306527SDavid du Colombier 		memset(mb, 0, sizeof(MetaBlock));
75*3be74836SDavid du Colombier 		return 0;
76d9306527SDavid du Colombier 	}
77d9306527SDavid du Colombier 
78d9306527SDavid du Colombier 	magic = U32GET(p);
79d9306527SDavid du Colombier 	if(magic != MetaMagic && magic != MetaMagic+1) {
80*3be74836SDavid du Colombier 		werrstr("bad meta block magic");
81*3be74836SDavid du Colombier 		return -1;
82d9306527SDavid du Colombier 	}
83d9306527SDavid du Colombier 	mb->size = U16GET(p+4);
84d9306527SDavid du Colombier 	mb->free = U16GET(p+6);
85d9306527SDavid du Colombier 	mb->maxindex = U16GET(p+8);
86d9306527SDavid du Colombier 	mb->nindex = U16GET(p+10);
87d9306527SDavid du Colombier 	mb->unbotch = (magic == MetaMagic+1);
88d9306527SDavid du Colombier 
89d9306527SDavid du Colombier 	if(mb->size > n) {
90*3be74836SDavid du Colombier 		werrstr("bad meta block size");
91*3be74836SDavid du Colombier 		return -1;
92d9306527SDavid du Colombier 	}
93d9306527SDavid du Colombier 	p += MetaHeaderSize;
94d9306527SDavid du Colombier 	n -= MetaHeaderSize;
95d9306527SDavid du Colombier 
96d9306527SDavid du Colombier 	USED(p);
97d9306527SDavid du Colombier 	if(n < mb->maxindex*MetaIndexSize) {
98*3be74836SDavid du Colombier  		werrstr("truncated meta block 2");
99*3be74836SDavid du Colombier 		return -1;
100d9306527SDavid du Colombier 	}
101*3be74836SDavid du Colombier 	return 0;
10249223a73SDavid du Colombier }
103d9306527SDavid du Colombier 
104d9306527SDavid du Colombier void
mbpack(MetaBlock * mb)105*3be74836SDavid du Colombier mbpack(MetaBlock *mb)
106d9306527SDavid du Colombier {
107d9306527SDavid du Colombier 	uchar *p;
108d9306527SDavid du Colombier 
109d9306527SDavid du Colombier 	p = mb->buf;
110d9306527SDavid du Colombier 
111d9306527SDavid du Colombier 	U32PUT(p, MetaMagic);
112d9306527SDavid du Colombier 	U16PUT(p+4, mb->size);
113d9306527SDavid du Colombier 	U16PUT(p+6, mb->free);
114d9306527SDavid du Colombier 	U16PUT(p+8, mb->maxindex);
115d9306527SDavid du Colombier 	U16PUT(p+10, mb->nindex);
116d9306527SDavid du Colombier }
117d9306527SDavid du Colombier 
118d9306527SDavid du Colombier 
119d9306527SDavid du Colombier void
mbdelete(MetaBlock * mb,int i,MetaEntry * me)120*3be74836SDavid du Colombier mbdelete(MetaBlock *mb, int i, MetaEntry *me)
121d9306527SDavid du Colombier {
122d9306527SDavid du Colombier 	uchar *p;
123d9306527SDavid du Colombier 	int n;
124d9306527SDavid du Colombier 
125d9306527SDavid du Colombier 	assert(i < mb->nindex);
126d9306527SDavid du Colombier 
127d9306527SDavid du Colombier 	if(me->p - mb->buf + me->size == mb->size)
128d9306527SDavid du Colombier 		mb->size -= me->size;
129d9306527SDavid du Colombier 	else
130d9306527SDavid du Colombier 		mb->free += me->size;
131d9306527SDavid du Colombier 
132d9306527SDavid du Colombier 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
133d9306527SDavid du Colombier 	n = (mb->nindex-i-1)*MetaIndexSize;
134d9306527SDavid du Colombier 	memmove(p, p+MetaIndexSize, n);
135d9306527SDavid du Colombier 	memset(p+n, 0, MetaIndexSize);
136d9306527SDavid du Colombier 	mb->nindex--;
137d9306527SDavid du Colombier }
138d9306527SDavid du Colombier 
139d9306527SDavid du Colombier void
mbinsert(MetaBlock * mb,int i,MetaEntry * me)140*3be74836SDavid du Colombier mbinsert(MetaBlock *mb, int i, MetaEntry *me)
141d9306527SDavid du Colombier {
142d9306527SDavid du Colombier 	uchar *p;
143d9306527SDavid du Colombier 	int o, n;
144d9306527SDavid du Colombier 
145d9306527SDavid du Colombier 	assert(mb->nindex < mb->maxindex);
146d9306527SDavid du Colombier 
147d9306527SDavid du Colombier 	o = me->p - mb->buf;
148d9306527SDavid du Colombier 	n = me->size;
149d9306527SDavid du Colombier 	if(o+n > mb->size) {
150d9306527SDavid du Colombier 		mb->free -= mb->size - o;
151d9306527SDavid du Colombier 		mb->size = o + n;
152d9306527SDavid du Colombier 	} else
153d9306527SDavid du Colombier 		mb->free -= n;
154d9306527SDavid du Colombier 
155d9306527SDavid du Colombier 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
156d9306527SDavid du Colombier 	n = (mb->nindex-i)*MetaIndexSize;
157d9306527SDavid du Colombier 	memmove(p+MetaIndexSize, p, n);
158d9306527SDavid du Colombier 	U16PUT(p, me->p - mb->buf);
159d9306527SDavid du Colombier 	U16PUT(p+2, me->size);
160d9306527SDavid du Colombier 	mb->nindex++;
161d9306527SDavid du Colombier }
162d9306527SDavid du Colombier 
163d9306527SDavid du Colombier int
meunpack(MetaEntry * me,MetaBlock * mb,int i)164*3be74836SDavid du Colombier meunpack(MetaEntry *me, MetaBlock *mb, int i)
165d9306527SDavid du Colombier {
166d9306527SDavid du Colombier 	uchar *p;
167d9306527SDavid du Colombier 	int eo, en;
168d9306527SDavid du Colombier 
169d9306527SDavid du Colombier 	if(i < 0 || i >= mb->nindex) {
170*3be74836SDavid du Colombier 		werrstr("bad meta entry index");
171*3be74836SDavid du Colombier 		return -1;
172d9306527SDavid du Colombier 	}
173d9306527SDavid du Colombier 
174d9306527SDavid du Colombier 	p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
175d9306527SDavid du Colombier 	eo = U16GET(p);
176d9306527SDavid du Colombier 	en = U16GET(p+2);
177d9306527SDavid du Colombier 
178d9306527SDavid du Colombier if(0)print("eo = %d en = %d\n", eo, en);
179d9306527SDavid du Colombier 	if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) {
180*3be74836SDavid du Colombier 		werrstr("corrupted entry in meta block");
181*3be74836SDavid du Colombier 		return -1;
182d9306527SDavid du Colombier 	}
183d9306527SDavid du Colombier 
184d9306527SDavid du Colombier 	if(eo+en > mb->size) {
185*3be74836SDavid du Colombier  		werrstr("truncated meta block");
186*3be74836SDavid du Colombier 		return -1;
187d9306527SDavid du Colombier 	}
188d9306527SDavid du Colombier 
189d9306527SDavid du Colombier 	p = mb->buf + eo;
190d9306527SDavid du Colombier 
191d9306527SDavid du Colombier 	/* make sure entry looks ok and includes an elem name */
192d9306527SDavid du Colombier 	if(en < 8 || U32GET(p) != DirMagic || en < 8 + U16GET(p+6)) {
193*3be74836SDavid du Colombier 		werrstr("corrupted meta block entry");
194*3be74836SDavid du Colombier 		return -1;
195d9306527SDavid du Colombier 	}
196d9306527SDavid du Colombier 
197d9306527SDavid du Colombier 	me->p = p;
198d9306527SDavid du Colombier 	me->size = en;
199d9306527SDavid du Colombier 
200*3be74836SDavid du Colombier 	return 0;
201d9306527SDavid du Colombier }
202d9306527SDavid du Colombier 
203*3be74836SDavid du Colombier /* assumes a small amount of checking has been done in mbentry */
204d9306527SDavid du Colombier int
mecmp(MetaEntry * me,char * s)205*3be74836SDavid du Colombier mecmp(MetaEntry *me, char *s)
206d9306527SDavid du Colombier {
207d9306527SDavid du Colombier 	int n;
208d9306527SDavid du Colombier 	uchar *p;
209d9306527SDavid du Colombier 
210d9306527SDavid du Colombier 	p = me->p;
211d9306527SDavid du Colombier 
212d9306527SDavid du Colombier 	p += 6;
213d9306527SDavid du Colombier 	n = U16GET(p);
214d9306527SDavid du Colombier 	p += 2;
215d9306527SDavid du Colombier 
216d9306527SDavid du Colombier 	assert(n + 8 < me->size);
217d9306527SDavid du Colombier 
218d9306527SDavid du Colombier 	while(n > 0) {
219d9306527SDavid du Colombier 		if(*s == 0)
220d9306527SDavid du Colombier 			return -1;
221d9306527SDavid du Colombier 		if(*p < (uchar)*s)
222d9306527SDavid du Colombier 			return -1;
223d9306527SDavid du Colombier 		if(*p > (uchar)*s)
224d9306527SDavid du Colombier 			return 1;
225d9306527SDavid du Colombier 		p++;
226d9306527SDavid du Colombier 		s++;
227d9306527SDavid du Colombier 		n--;
228d9306527SDavid du Colombier 	}
229d9306527SDavid du Colombier 	return *s != 0;
230d9306527SDavid du Colombier }
231d9306527SDavid du Colombier 
232d9306527SDavid du Colombier int
mecmpnew(MetaEntry * me,char * s)233*3be74836SDavid du Colombier mecmpnew(MetaEntry *me, char *s)
234d9306527SDavid du Colombier {
235d9306527SDavid du Colombier 	int n;
236d9306527SDavid du Colombier 	uchar *p;
237d9306527SDavid du Colombier 
238d9306527SDavid du Colombier 	p = me->p;
239d9306527SDavid du Colombier 
240d9306527SDavid du Colombier 	p += 6;
241d9306527SDavid du Colombier 	n = U16GET(p);
242d9306527SDavid du Colombier 	p += 2;
243d9306527SDavid du Colombier 
244d9306527SDavid du Colombier 	assert(n + 8 < me->size);
245d9306527SDavid du Colombier 
246d9306527SDavid du Colombier 	while(n > 0) {
247d9306527SDavid du Colombier 		if(*s == 0)
248d9306527SDavid du Colombier 			return 1;
249d9306527SDavid du Colombier 		if(*p < (uchar)*s)
250d9306527SDavid du Colombier 			return -1;
251d9306527SDavid du Colombier 		if(*p > (uchar)*s)
252d9306527SDavid du Colombier 			return 1;
253d9306527SDavid du Colombier 		p++;
254d9306527SDavid du Colombier 		s++;
255d9306527SDavid du Colombier 		n--;
256d9306527SDavid du Colombier 	}
257d9306527SDavid du Colombier 	return -(*s != 0);
258d9306527SDavid du Colombier }
259d9306527SDavid du Colombier 
260d9306527SDavid du Colombier static int
offsetcmp(const void * s0,const void * s1)261*3be74836SDavid du Colombier offsetcmp(const void *s0, const void *s1)
262d9306527SDavid du Colombier {
263*3be74836SDavid du Colombier 	const MetaChunk *mc0, *mc1;
264d9306527SDavid du Colombier 
265d9306527SDavid du Colombier 	mc0 = s0;
266d9306527SDavid du Colombier 	mc1 = s1;
267d9306527SDavid du Colombier 	if(mc0->offset < mc1->offset)
268d9306527SDavid du Colombier 		return -1;
269d9306527SDavid du Colombier 	if(mc0->offset > mc1->offset)
270d9306527SDavid du Colombier 		return 1;
271d9306527SDavid du Colombier 	return 0;
272d9306527SDavid du Colombier }
273d9306527SDavid du Colombier 
274d9306527SDavid du Colombier static MetaChunk *
metachunks(MetaBlock * mb)275*3be74836SDavid du Colombier metachunks(MetaBlock *mb)
276d9306527SDavid du Colombier {
277d9306527SDavid du Colombier 	MetaChunk *mc;
278d9306527SDavid du Colombier 	int oo, o, n, i;
279d9306527SDavid du Colombier 	uchar *p;
280d9306527SDavid du Colombier 
281*3be74836SDavid du Colombier 	mc = vtmalloc(mb->nindex*sizeof(MetaChunk));
282d9306527SDavid du Colombier 	p = mb->buf + MetaHeaderSize;
283d9306527SDavid du Colombier 	for(i = 0; i<mb->nindex; i++) {
284d9306527SDavid du Colombier 		mc[i].offset = U16GET(p);
285d9306527SDavid du Colombier 		mc[i].size = U16GET(p+2);
286d9306527SDavid du Colombier 		mc[i].index = i;
287d9306527SDavid du Colombier 		p += MetaIndexSize;
288d9306527SDavid du Colombier 	}
289d9306527SDavid du Colombier 
290*3be74836SDavid du Colombier 	qsort(mc, mb->nindex, sizeof(MetaChunk), offsetcmp);
291d9306527SDavid du Colombier 
292d9306527SDavid du Colombier 	/* check block looks ok */
293d9306527SDavid du Colombier 	oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
294d9306527SDavid du Colombier 	o = oo;
295d9306527SDavid du Colombier 	n = 0;
296d9306527SDavid du Colombier 	for(i=0; i<mb->nindex; i++) {
297d9306527SDavid du Colombier 		o = mc[i].offset;
298d9306527SDavid du Colombier 		n = mc[i].size;
299d9306527SDavid du Colombier 		if(o < oo)
300d9306527SDavid du Colombier 			goto Err;
301d9306527SDavid du Colombier 		oo += n;
302d9306527SDavid du Colombier 	}
303d9306527SDavid du Colombier 	if(o+n <= mb->size)
304d9306527SDavid du Colombier 		goto Err;
305d9306527SDavid du Colombier 	if(mb->size - oo != mb->free)
306d9306527SDavid du Colombier 		goto Err;
307d9306527SDavid du Colombier 
308d9306527SDavid du Colombier 	return mc;
309d9306527SDavid du Colombier Err:
310*3be74836SDavid du Colombier 	vtfree(mc);
311d9306527SDavid du Colombier 	return nil;
312d9306527SDavid du Colombier }
313d9306527SDavid du Colombier 
314d9306527SDavid du Colombier static void
mbcompact(MetaBlock * mb,MetaChunk * mc)315*3be74836SDavid du Colombier mbcompact(MetaBlock *mb, MetaChunk *mc)
316d9306527SDavid du Colombier {
317d9306527SDavid du Colombier 	int oo, o, n, i;
318d9306527SDavid du Colombier 
319d9306527SDavid du Colombier 	oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
320d9306527SDavid du Colombier 
321d9306527SDavid du Colombier 	for(i=0; i<mb->nindex; i++) {
322d9306527SDavid du Colombier 		o = mc[i].offset;
323d9306527SDavid du Colombier 		n = mc[i].size;
324d9306527SDavid du Colombier 		if(o != oo) {
325d9306527SDavid du Colombier 			memmove(mb->buf + oo, mb->buf + o, n);
326d9306527SDavid du Colombier 			U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
327d9306527SDavid du Colombier 		}
328d9306527SDavid du Colombier 		oo += n;
329d9306527SDavid du Colombier 	}
330d9306527SDavid du Colombier 
331d9306527SDavid du Colombier 	mb->size = oo;
332d9306527SDavid du Colombier 	mb->free = 0;
333d9306527SDavid du Colombier }
334d9306527SDavid du Colombier 
335d9306527SDavid du Colombier uchar *
mballoc(MetaBlock * mb,int n)336*3be74836SDavid du Colombier mballoc(MetaBlock *mb, int n)
337d9306527SDavid du Colombier {
338d9306527SDavid du Colombier 	int i, o;
339d9306527SDavid du Colombier 	MetaChunk *mc;
340d9306527SDavid du Colombier 
341d9306527SDavid du Colombier 	/* off the end */
342d9306527SDavid du Colombier 	if(mb->maxsize - mb->size >= n)
343d9306527SDavid du Colombier 		return mb->buf + mb->size;
344d9306527SDavid du Colombier 
345d9306527SDavid du Colombier 	/* check if possible */
346d9306527SDavid du Colombier 	if(mb->maxsize - mb->size + mb->free < n)
347d9306527SDavid du Colombier 		return nil;
348d9306527SDavid du Colombier 
349*3be74836SDavid du Colombier 	mc = metachunks(mb);
350d9306527SDavid du Colombier 
351d9306527SDavid du Colombier 	/* look for hole */
352d9306527SDavid du Colombier 	o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
353d9306527SDavid du Colombier 	for(i=0; i<mb->nindex; i++) {
354d9306527SDavid du Colombier 		if(mc[i].offset - o >= n) {
355*3be74836SDavid du Colombier 			vtfree(mc);
356d9306527SDavid du Colombier 			return mb->buf + o;
357d9306527SDavid du Colombier 		}
358d9306527SDavid du Colombier 		o = mc[i].offset + mc[i].size;
359d9306527SDavid du Colombier 	}
360d9306527SDavid du Colombier 
361d9306527SDavid du Colombier 	if(mb->maxsize - o >= n) {
362*3be74836SDavid du Colombier 		vtfree(mc);
363d9306527SDavid du Colombier 		return mb->buf + o;
364d9306527SDavid du Colombier 	}
365d9306527SDavid du Colombier 
366d9306527SDavid du Colombier 	/* compact and return off the end */
367*3be74836SDavid du Colombier 	mbcompact(mb, mc);
368*3be74836SDavid du Colombier 	vtfree(mc);
369d9306527SDavid du Colombier 
370d9306527SDavid du Colombier 	assert(mb->maxsize - mb->size >= n);
371d9306527SDavid du Colombier 	return mb->buf + mb->size;
372d9306527SDavid du Colombier }
373d9306527SDavid du Colombier 
374d9306527SDavid du Colombier int
vdsize(VacDir * dir,int version)375*3be74836SDavid du Colombier vdsize(VacDir *dir, int version)
376d9306527SDavid du Colombier {
377d9306527SDavid du Colombier 	int n;
378d9306527SDavid du Colombier 
379*3be74836SDavid du Colombier 	if(version < 8 || version > 9)
380*3be74836SDavid du Colombier 		sysfatal("bad version %d in vdpack", version);
38149223a73SDavid du Colombier 
382*3be74836SDavid du Colombier 	/* constant part */
383d9306527SDavid du Colombier 	n = 	4 +	/* magic */
384d9306527SDavid du Colombier 		2 + 	/* version */
385d9306527SDavid du Colombier 		4 +	/* entry */
386d9306527SDavid du Colombier 		8 +	/* qid */
387d9306527SDavid du Colombier 		4 + 	/* mtime */
388d9306527SDavid du Colombier 		4 + 	/* mcount */
389d9306527SDavid du Colombier 		4 + 	/* ctime */
390d9306527SDavid du Colombier 		4 + 	/* atime */
391d9306527SDavid du Colombier 		4 +	/* mode */
392d9306527SDavid du Colombier 		0;
393d9306527SDavid du Colombier 
394*3be74836SDavid du Colombier 	if(version == 9){
395*3be74836SDavid du Colombier 		n += 	4 +	/* gen */
396*3be74836SDavid du Colombier 			4 + 	/* mentry */
397*3be74836SDavid du Colombier 			4 + 	/* mgen */
398*3be74836SDavid du Colombier 			0;
399*3be74836SDavid du Colombier 	}
400*3be74836SDavid du Colombier 
401d9306527SDavid du Colombier 	/* strings */
402d9306527SDavid du Colombier 	n += 2 + strlen(dir->elem);
403d9306527SDavid du Colombier 	n += 2 + strlen(dir->uid);
404d9306527SDavid du Colombier 	n += 2 + strlen(dir->gid);
405d9306527SDavid du Colombier 	n += 2 + strlen(dir->mid);
406d9306527SDavid du Colombier 
407d9306527SDavid du Colombier 	/* optional sections */
408*3be74836SDavid du Colombier 	if(version < 9 && dir->plan9) {
409d9306527SDavid du Colombier 		n += 	3 + 	/* option header */
410*3be74836SDavid du Colombier 			8 + 	/* path */
411*3be74836SDavid du Colombier 			4;	/* version */
412*3be74836SDavid du Colombier 	}
413*3be74836SDavid du Colombier 	if(dir->qidspace) {
414*3be74836SDavid du Colombier 		n += 	3 + 	/* option header */
415*3be74836SDavid du Colombier 			8 + 	/* qid offset */
416*3be74836SDavid du Colombier 			8;	/* qid max */
417*3be74836SDavid du Colombier 	}
418*3be74836SDavid du Colombier 	if(version < 9 && dir->gen) {
419*3be74836SDavid du Colombier 		n += 	3 + 	/* option header */
420*3be74836SDavid du Colombier 			4;	/* gen */
421d9306527SDavid du Colombier 	}
422d9306527SDavid du Colombier 
423d9306527SDavid du Colombier 	return n;
424d9306527SDavid du Colombier }
425d9306527SDavid du Colombier 
426d9306527SDavid du Colombier void
vdpack(VacDir * dir,MetaEntry * me,int version)427*3be74836SDavid du Colombier vdpack(VacDir *dir, MetaEntry *me, int version)
428d9306527SDavid du Colombier {
429d9306527SDavid du Colombier 	uchar *p;
430d9306527SDavid du Colombier 	ulong t32;
431d9306527SDavid du Colombier 
432*3be74836SDavid du Colombier 	if(version < 8 || version > 9)
433*3be74836SDavid du Colombier 		sysfatal("bad version %d in vdpack", version);
434*3be74836SDavid du Colombier 
435d9306527SDavid du Colombier 	p = me->p;
436d9306527SDavid du Colombier 
437d9306527SDavid du Colombier 	U32PUT(p, DirMagic);
438*3be74836SDavid du Colombier 	U16PUT(p+4, version);		/* version */
439d9306527SDavid du Colombier 	p += 6;
440d9306527SDavid du Colombier 
441*3be74836SDavid du Colombier 	p += stringpack(dir->elem, p);
442d9306527SDavid du Colombier 
443d9306527SDavid du Colombier 	U32PUT(p, dir->entry);
444*3be74836SDavid du Colombier 	p += 4;
445d9306527SDavid du Colombier 
446*3be74836SDavid du Colombier 	if(version == 9){
447*3be74836SDavid du Colombier 		U32PUT(p, dir->gen);
448*3be74836SDavid du Colombier 		U32PUT(p+4, dir->mentry);
449*3be74836SDavid du Colombier 		U32PUT(p+8, dir->mgen);
450*3be74836SDavid du Colombier 		p += 12;
451*3be74836SDavid du Colombier 	}
452*3be74836SDavid du Colombier 
453*3be74836SDavid du Colombier 	U64PUT(p, dir->qid, t32);
454*3be74836SDavid du Colombier 	p += 8;
455*3be74836SDavid du Colombier 
456*3be74836SDavid du Colombier 	p += stringpack(dir->uid, p);
457*3be74836SDavid du Colombier 	p += stringpack(dir->gid, p);
458*3be74836SDavid du Colombier 	p += stringpack(dir->mid, p);
459d9306527SDavid du Colombier 
460d9306527SDavid du Colombier 	U32PUT(p, dir->mtime);
461d9306527SDavid du Colombier 	U32PUT(p+4, dir->mcount);
462d9306527SDavid du Colombier 	U32PUT(p+8, dir->ctime);
463d9306527SDavid du Colombier 	U32PUT(p+12, dir->atime);
464d9306527SDavid du Colombier 	U32PUT(p+16, dir->mode);
465d9306527SDavid du Colombier 	p += 5*4;
466d9306527SDavid du Colombier 
467*3be74836SDavid du Colombier 	if(dir->plan9 && version < 9) {
468*3be74836SDavid du Colombier 		U8PUT(p, DirPlan9Entry);
469*3be74836SDavid du Colombier 		U16PUT(p+1, 8+4);
470*3be74836SDavid du Colombier 		p += 3;
471*3be74836SDavid du Colombier 		U64PUT(p, dir->p9path, t32);
472*3be74836SDavid du Colombier 		U32PUT(p+8, dir->p9version);
473*3be74836SDavid du Colombier 		p += 12;
474*3be74836SDavid du Colombier 	}
475*3be74836SDavid du Colombier 
476*3be74836SDavid du Colombier 	if(dir->qidspace) {
477d9306527SDavid du Colombier 		U8PUT(p, DirQidSpaceEntry);
478d9306527SDavid du Colombier 		U16PUT(p+1, 2*8);
479d9306527SDavid du Colombier 		p += 3;
480*3be74836SDavid du Colombier 		U64PUT(p, dir->qidoffset, t32);
481*3be74836SDavid du Colombier 		U64PUT(p+8, dir->qidmax, t32);
482*3be74836SDavid du Colombier 		p += 16;
483*3be74836SDavid du Colombier 	}
484*3be74836SDavid du Colombier 
485*3be74836SDavid du Colombier 	if(dir->gen && version < 9) {
486*3be74836SDavid du Colombier 		U8PUT(p, DirGenEntry);
487*3be74836SDavid du Colombier 		U16PUT(p+1, 4);
488*3be74836SDavid du Colombier 		p += 3;
489*3be74836SDavid du Colombier 		U32PUT(p, dir->gen);
490*3be74836SDavid du Colombier 		p += 4;
491d9306527SDavid du Colombier 	}
492d9306527SDavid du Colombier 
493d9306527SDavid du Colombier 	assert(p == me->p + me->size);
494d9306527SDavid du Colombier }
495d9306527SDavid du Colombier 
496d9306527SDavid du Colombier int
vdunpack(VacDir * dir,MetaEntry * me)497*3be74836SDavid du Colombier vdunpack(VacDir *dir, MetaEntry *me)
498d9306527SDavid du Colombier {
499d9306527SDavid du Colombier 	int t, nn, n, version;
500d9306527SDavid du Colombier 	uchar *p;
501d9306527SDavid du Colombier 
502d9306527SDavid du Colombier 	p = me->p;
503d9306527SDavid du Colombier 	n = me->size;
504d9306527SDavid du Colombier 
505d9306527SDavid du Colombier 	memset(dir, 0, sizeof(VacDir));
506d9306527SDavid du Colombier 
507d9306527SDavid du Colombier 	/* magic */
508d9306527SDavid du Colombier 	if(n < 4 || U32GET(p) != DirMagic)
509d9306527SDavid du Colombier 		goto Err;
510d9306527SDavid du Colombier 	p += 4;
511d9306527SDavid du Colombier 	n -= 4;
512d9306527SDavid du Colombier 
513d9306527SDavid du Colombier 	/* version */
514d9306527SDavid du Colombier 	if(n < 2)
515d9306527SDavid du Colombier 		goto Err;
516d9306527SDavid du Colombier 	version = U16GET(p);
517d9306527SDavid du Colombier 	if(version < 7 || version > 9)
518d9306527SDavid du Colombier 		goto Err;
519d9306527SDavid du Colombier 	p += 2;
520d9306527SDavid du Colombier 	n -= 2;
521d9306527SDavid du Colombier 
522d9306527SDavid du Colombier 	/* elem */
523*3be74836SDavid du Colombier 	if(stringunpack(&dir->elem, &p, &n) < 0)
524d9306527SDavid du Colombier 		goto Err;
525d9306527SDavid du Colombier 
526d9306527SDavid du Colombier 	/* entry  */
527d9306527SDavid du Colombier 	if(n < 4)
528d9306527SDavid du Colombier 		goto Err;
529d9306527SDavid du Colombier 	dir->entry = U32GET(p);
530d9306527SDavid du Colombier 	p += 4;
531d9306527SDavid du Colombier 	n -= 4;
532d9306527SDavid du Colombier 
533d9306527SDavid du Colombier 	if(version < 9) {
534d9306527SDavid du Colombier 		dir->gen = 0;
535d9306527SDavid du Colombier 		dir->mentry = dir->entry+1;
536d9306527SDavid du Colombier 		dir->mgen = 0;
537d9306527SDavid du Colombier 	} else {
538d9306527SDavid du Colombier 		if(n < 3*4)
539d9306527SDavid du Colombier 			goto Err;
540d9306527SDavid du Colombier 		dir->gen = U32GET(p);
541d9306527SDavid du Colombier 		dir->mentry = U32GET(p+4);
542d9306527SDavid du Colombier 		dir->mgen = U32GET(p+8);
543d9306527SDavid du Colombier 		p += 3*4;
544d9306527SDavid du Colombier 		n -= 3*4;
545d9306527SDavid du Colombier 	}
546d9306527SDavid du Colombier 
547d9306527SDavid du Colombier 	/* size is gotten from DirEntry */
548d9306527SDavid du Colombier 
549d9306527SDavid du Colombier 	/* qid */
550d9306527SDavid du Colombier 	if(n < 8)
551d9306527SDavid du Colombier 		goto Err;
552d9306527SDavid du Colombier 	dir->qid = U64GET(p);
553d9306527SDavid du Colombier 	p += 8;
554d9306527SDavid du Colombier 	n -= 8;
555d9306527SDavid du Colombier 
556d9306527SDavid du Colombier 	/* skip replacement */
557d9306527SDavid du Colombier 	if(version == 7) {
558d9306527SDavid du Colombier 		if(n < VtScoreSize)
559d9306527SDavid du Colombier 			goto Err;
560d9306527SDavid du Colombier 		p += VtScoreSize;
561d9306527SDavid du Colombier 		n -= VtScoreSize;
562d9306527SDavid du Colombier 	}
563d9306527SDavid du Colombier 
564d9306527SDavid du Colombier 	/* uid */
565*3be74836SDavid du Colombier 	if(stringunpack(&dir->uid, &p, &n) < 0)
566d9306527SDavid du Colombier 		goto Err;
567d9306527SDavid du Colombier 
568d9306527SDavid du Colombier 	/* gid */
569*3be74836SDavid du Colombier 	if(stringunpack(&dir->gid, &p, &n) < 0)
570d9306527SDavid du Colombier 		goto Err;
571d9306527SDavid du Colombier 
572d9306527SDavid du Colombier 	/* mid */
573*3be74836SDavid du Colombier 	if(stringunpack(&dir->mid, &p, &n) < 0)
574d9306527SDavid du Colombier 		goto Err;
575d9306527SDavid du Colombier 
576d9306527SDavid du Colombier 	if(n < 5*4)
577d9306527SDavid du Colombier 		goto Err;
578d9306527SDavid du Colombier 	dir->mtime = U32GET(p);
579d9306527SDavid du Colombier 	dir->mcount = U32GET(p+4);
580d9306527SDavid du Colombier 	dir->ctime = U32GET(p+8);
581d9306527SDavid du Colombier 	dir->atime = U32GET(p+12);
582d9306527SDavid du Colombier 	dir->mode = U32GET(p+16);
583d9306527SDavid du Colombier 	p += 5*4;
584d9306527SDavid du Colombier 	n -= 5*4;
585d9306527SDavid du Colombier 
586d9306527SDavid du Colombier 	/* optional meta data */
587d9306527SDavid du Colombier 	while(n > 0) {
588d9306527SDavid du Colombier 		if(n < 3)
589d9306527SDavid du Colombier 			goto Err;
590d9306527SDavid du Colombier 		t = p[0];
591d9306527SDavid du Colombier 		nn = U16GET(p+1);
592d9306527SDavid du Colombier 		p += 3;
593d9306527SDavid du Colombier 		n -= 3;
594d9306527SDavid du Colombier 		if(n < nn)
595d9306527SDavid du Colombier 			goto Err;
596d9306527SDavid du Colombier 		switch(t) {
597d9306527SDavid du Colombier 		case DirPlan9Entry:
598d9306527SDavid du Colombier 			/* not valid in version >= 9 */
599d9306527SDavid du Colombier 			if(version >= 9)
600d9306527SDavid du Colombier 				break;
601d9306527SDavid du Colombier 			if(dir->plan9 || nn != 12)
602d9306527SDavid du Colombier 				goto Err;
603d9306527SDavid du Colombier 			dir->plan9 = 1;
604d9306527SDavid du Colombier 			dir->p9path = U64GET(p);
605d9306527SDavid du Colombier 			dir->p9version = U32GET(p+8);
606d9306527SDavid du Colombier 			if(dir->mcount == 0)
607d9306527SDavid du Colombier 				dir->mcount = dir->p9version;
608d9306527SDavid du Colombier 			break;
609d9306527SDavid du Colombier 		case DirGenEntry:
610d9306527SDavid du Colombier 			/* not valid in version >= 9 */
611d9306527SDavid du Colombier 			if(version >= 9)
612d9306527SDavid du Colombier 				break;
613d9306527SDavid du Colombier 			break;
614d9306527SDavid du Colombier 		case DirQidSpaceEntry:
615*3be74836SDavid du Colombier 			if(dir->qidspace || nn != 16)
616d9306527SDavid du Colombier 				goto Err;
617*3be74836SDavid du Colombier 			dir->qidspace = 1;
618*3be74836SDavid du Colombier 			dir->qidoffset = U64GET(p);
619*3be74836SDavid du Colombier 			dir->qidmax = U64GET(p+8);
620d9306527SDavid du Colombier 			break;
621d9306527SDavid du Colombier 		}
622d9306527SDavid du Colombier 		p += nn;
623d9306527SDavid du Colombier 		n -= nn;
624d9306527SDavid du Colombier 	}
625d9306527SDavid du Colombier 
626d9306527SDavid du Colombier 	if(p != me->p + me->size)
627d9306527SDavid du Colombier 		goto Err;
628d9306527SDavid du Colombier 
629e538c934SDavid du Colombier 	return 0;
630*3be74836SDavid du Colombier Err:
631*3be74836SDavid du Colombier 	werrstr(EBadMeta);
632*3be74836SDavid du Colombier 	vdcleanup(dir);
633*3be74836SDavid du Colombier 	return -1;
634*3be74836SDavid du Colombier }
635*3be74836SDavid du Colombier 
636*3be74836SDavid du Colombier void
vdcleanup(VacDir * dir)637*3be74836SDavid du Colombier vdcleanup(VacDir *dir)
638*3be74836SDavid du Colombier {
639*3be74836SDavid du Colombier 	vtfree(dir->elem);
640*3be74836SDavid du Colombier 	dir->elem = nil;
641*3be74836SDavid du Colombier 	vtfree(dir->uid);
642*3be74836SDavid du Colombier 	dir->uid = nil;
643*3be74836SDavid du Colombier 	vtfree(dir->gid);
644*3be74836SDavid du Colombier 	dir->gid = nil;
645*3be74836SDavid du Colombier 	vtfree(dir->mid);
646*3be74836SDavid du Colombier 	dir->mid = nil;
647*3be74836SDavid du Colombier }
648*3be74836SDavid du Colombier 
649*3be74836SDavid du Colombier void
vdcopy(VacDir * dst,VacDir * src)650*3be74836SDavid du Colombier vdcopy(VacDir *dst, VacDir *src)
651*3be74836SDavid du Colombier {
652*3be74836SDavid du Colombier 	*dst = *src;
653*3be74836SDavid du Colombier 	dst->elem = vtstrdup(dst->elem);
654*3be74836SDavid du Colombier 	dst->uid = vtstrdup(dst->uid);
655*3be74836SDavid du Colombier 	dst->gid = vtstrdup(dst->gid);
656*3be74836SDavid du Colombier 	dst->mid = vtstrdup(dst->mid);
657*3be74836SDavid du Colombier }
658*3be74836SDavid du Colombier 
659*3be74836SDavid du Colombier int
mbsearch(MetaBlock * mb,char * elem,int * ri,MetaEntry * me)660*3be74836SDavid du Colombier mbsearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
661*3be74836SDavid du Colombier {
662*3be74836SDavid du Colombier 	int i;
663*3be74836SDavid du Colombier 	int b, t, x;
664*3be74836SDavid du Colombier 
665*3be74836SDavid du Colombier 	/* binary search within block */
666*3be74836SDavid du Colombier 	b = 0;
667*3be74836SDavid du Colombier 	t = mb->nindex;
668*3be74836SDavid du Colombier 	while(b < t) {
669*3be74836SDavid du Colombier 		i = (b+t)>>1;
670*3be74836SDavid du Colombier 		if(meunpack(me, mb, i) < 0)
671*3be74836SDavid du Colombier 			return 0;
672*3be74836SDavid du Colombier 		if(mb->unbotch)
673*3be74836SDavid du Colombier 			x = mecmpnew(me, elem);
674*3be74836SDavid du Colombier 		else
675*3be74836SDavid du Colombier 			x = mecmp(me, elem);
676*3be74836SDavid du Colombier 
677*3be74836SDavid du Colombier 		if(x == 0) {
678*3be74836SDavid du Colombier 			*ri = i;
679*3be74836SDavid du Colombier 			return 1;
680*3be74836SDavid du Colombier 		}
681*3be74836SDavid du Colombier 
682*3be74836SDavid du Colombier 		if(x < 0)
683*3be74836SDavid du Colombier 			b = i+1;
684*3be74836SDavid du Colombier 		else /* x > 0 */
685*3be74836SDavid du Colombier 			t = i;
686*3be74836SDavid du Colombier 	}
687*3be74836SDavid du Colombier 
688*3be74836SDavid du Colombier 	assert(b == t);
689*3be74836SDavid du Colombier 
690*3be74836SDavid du Colombier 	*ri = b;	/* b is the index to insert this entry */
691*3be74836SDavid du Colombier 	memset(me, 0, sizeof(*me));
692*3be74836SDavid du Colombier 
693*3be74836SDavid du Colombier 	return -1;
694*3be74836SDavid du Colombier }
695*3be74836SDavid du Colombier 
696*3be74836SDavid du Colombier void
mbinit(MetaBlock * mb,uchar * p,int n,int entries)697*3be74836SDavid du Colombier mbinit(MetaBlock *mb, uchar *p, int n, int entries)
698*3be74836SDavid du Colombier {
699*3be74836SDavid du Colombier 	memset(mb, 0, sizeof(MetaBlock));
700*3be74836SDavid du Colombier 	mb->maxsize = n;
701*3be74836SDavid du Colombier 	mb->buf = p;
702*3be74836SDavid du Colombier 	mb->maxindex = entries;
703*3be74836SDavid du Colombier 	mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize;
704*3be74836SDavid du Colombier }
705*3be74836SDavid du Colombier 
706*3be74836SDavid du Colombier int
mbresize(MetaBlock * mb,MetaEntry * me,int n)707*3be74836SDavid du Colombier mbresize(MetaBlock *mb, MetaEntry *me, int n)
708*3be74836SDavid du Colombier {
709*3be74836SDavid du Colombier 	uchar *p, *ep;
710*3be74836SDavid du Colombier 
711*3be74836SDavid du Colombier 	/* easy case */
712*3be74836SDavid du Colombier 	if(n <= me->size){
713*3be74836SDavid du Colombier 		me->size = n;
714*3be74836SDavid du Colombier 		return 0;
715*3be74836SDavid du Colombier 	}
716*3be74836SDavid du Colombier 
717*3be74836SDavid du Colombier 	/* try and expand entry */
718*3be74836SDavid du Colombier 
719*3be74836SDavid du Colombier 	p = me->p + me->size;
720*3be74836SDavid du Colombier 	ep = mb->buf + mb->maxsize;
721*3be74836SDavid du Colombier 	while(p < ep && *p == 0)
722*3be74836SDavid du Colombier 		p++;
723*3be74836SDavid du Colombier 	if(n <= p - me->p){
724*3be74836SDavid du Colombier 		me->size = n;
725*3be74836SDavid du Colombier 		return 0;
726*3be74836SDavid du Colombier 	}
727*3be74836SDavid du Colombier 
728*3be74836SDavid du Colombier 	p = mballoc(mb, n);
729*3be74836SDavid du Colombier 	if(p != nil){
730*3be74836SDavid du Colombier 		me->p = p;
731*3be74836SDavid du Colombier 		me->size = n;
732*3be74836SDavid du Colombier 		return 0;
733*3be74836SDavid du Colombier 	}
734*3be74836SDavid du Colombier 
735*3be74836SDavid du Colombier 	return -1;
736e538c934SDavid du Colombier }
737