xref: /plan9/sys/src/cmd/venti/srv/conv.c (revision b8a11165c6411897fdf740a1fb2f87ac0998b113)
1368c31abSDavid du Colombier #include "stdinc.h"
2368c31abSDavid du Colombier #include "dat.h"
3368c31abSDavid du Colombier #include "fns.h"
4368c31abSDavid du Colombier 
5368c31abSDavid du Colombier /*
6368c31abSDavid du Colombier  * disk structure conversion routines
7368c31abSDavid du Colombier  */
8368c31abSDavid du Colombier #define	U8GET(p)	((p)[0])
9368c31abSDavid du Colombier #define	U16GET(p)	(((p)[0]<<8)|(p)[1])
10368c31abSDavid du Colombier #define	U32GET(p)	((u32int)(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3]))
11368c31abSDavid du Colombier #define	U64GET(p)	(((u64int)U32GET(p)<<32)|(u64int)U32GET((p)+4))
12368c31abSDavid du Colombier 
13368c31abSDavid du Colombier #define	U8PUT(p,v)	(p)[0]=(v)&0xFF
14368c31abSDavid du Colombier #define	U16PUT(p,v)	(p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF
15368c31abSDavid 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
16368c31abSDavid du Colombier #define	U64PUT(p,v,t32)	t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
17368c31abSDavid du Colombier 
18*b8a11165SDavid du Colombier int debugarena = -1;		/* hack to improve error reporting */
19*b8a11165SDavid du Colombier 
20368c31abSDavid du Colombier static struct {
21368c31abSDavid du Colombier 	u32int m;
22368c31abSDavid du Colombier 	char *s;
23368c31abSDavid du Colombier } magics[] = {
24368c31abSDavid du Colombier 	ArenaPartMagic, "ArenaPartMagic",
25368c31abSDavid du Colombier 	ArenaHeadMagic, "ArenaHeadMagic",
26368c31abSDavid du Colombier 	ArenaMagic, "ArenaMagic",
27368c31abSDavid du Colombier 	ISectMagic, "ISectMagic",
28368c31abSDavid du Colombier 	BloomMagic, "BloomMagic",
29368c31abSDavid du Colombier };
30368c31abSDavid du Colombier 
31368c31abSDavid du Colombier static char*
fmtmagic(char * s,u32int m)32368c31abSDavid du Colombier fmtmagic(char *s, u32int m)
33368c31abSDavid du Colombier {
34368c31abSDavid du Colombier 	int i;
35368c31abSDavid du Colombier 
36368c31abSDavid du Colombier 	for(i=0; i<nelem(magics); i++)
37368c31abSDavid du Colombier 		if(magics[i].m == m)
38368c31abSDavid du Colombier 			return magics[i].s;
39368c31abSDavid du Colombier 	sprint(s, "%#08ux", m);
40368c31abSDavid du Colombier 	return s;
41368c31abSDavid du Colombier }
42368c31abSDavid du Colombier 
43368c31abSDavid du Colombier u32int
unpackmagic(u8int * buf)44368c31abSDavid du Colombier unpackmagic(u8int *buf)
45368c31abSDavid du Colombier {
46368c31abSDavid du Colombier 	return U32GET(buf);
47368c31abSDavid du Colombier }
48368c31abSDavid du Colombier 
49368c31abSDavid du Colombier void
packmagic(u32int magic,u8int * buf)50368c31abSDavid du Colombier packmagic(u32int magic, u8int *buf)
51368c31abSDavid du Colombier {
52368c31abSDavid du Colombier 	U32PUT(buf, magic);
53368c31abSDavid du Colombier }
54368c31abSDavid du Colombier 
55368c31abSDavid du Colombier int
unpackarenapart(ArenaPart * ap,u8int * buf)56368c31abSDavid du Colombier unpackarenapart(ArenaPart *ap, u8int *buf)
57368c31abSDavid du Colombier {
58368c31abSDavid du Colombier 	u8int *p;
59368c31abSDavid du Colombier 	u32int m;
60368c31abSDavid du Colombier 	char fbuf[20];
61368c31abSDavid du Colombier 
62368c31abSDavid du Colombier 	p = buf;
63368c31abSDavid du Colombier 
64368c31abSDavid du Colombier 	m = U32GET(p);
65368c31abSDavid du Colombier 	if(m != ArenaPartMagic){
66368c31abSDavid du Colombier 		seterr(ECorrupt, "arena set has wrong magic number: %s expected ArenaPartMagic (%#lux)", fmtmagic(fbuf, m), ArenaPartMagic);
67368c31abSDavid du Colombier 		return -1;
68368c31abSDavid du Colombier 	}
69368c31abSDavid du Colombier 	p += U32Size;
70368c31abSDavid du Colombier 	ap->version = U32GET(p);
71368c31abSDavid du Colombier 	p += U32Size;
72368c31abSDavid du Colombier 	ap->blocksize = U32GET(p);
73368c31abSDavid du Colombier 	p += U32Size;
74368c31abSDavid du Colombier 	ap->arenabase = U32GET(p);
75368c31abSDavid du Colombier 	p += U32Size;
76368c31abSDavid du Colombier 
77368c31abSDavid du Colombier 	if(buf + ArenaPartSize != p)
78368c31abSDavid du Colombier 		sysfatal("unpackarenapart unpacked wrong amount");
79368c31abSDavid du Colombier 
80368c31abSDavid du Colombier 	return 0;
81368c31abSDavid du Colombier }
82368c31abSDavid du Colombier 
83368c31abSDavid du Colombier int
packarenapart(ArenaPart * ap,u8int * buf)84368c31abSDavid du Colombier packarenapart(ArenaPart *ap, u8int *buf)
85368c31abSDavid du Colombier {
86368c31abSDavid du Colombier 	u8int *p;
87368c31abSDavid du Colombier 
88368c31abSDavid du Colombier 	p = buf;
89368c31abSDavid du Colombier 
90368c31abSDavid du Colombier 	U32PUT(p, ArenaPartMagic);
91368c31abSDavid du Colombier 	p += U32Size;
92368c31abSDavid du Colombier 	U32PUT(p, ap->version);
93368c31abSDavid du Colombier 	p += U32Size;
94368c31abSDavid du Colombier 	U32PUT(p, ap->blocksize);
95368c31abSDavid du Colombier 	p += U32Size;
96368c31abSDavid du Colombier 	U32PUT(p, ap->arenabase);
97368c31abSDavid du Colombier 	p += U32Size;
98368c31abSDavid du Colombier 
99368c31abSDavid du Colombier 	if(buf + ArenaPartSize != p)
100368c31abSDavid du Colombier 		sysfatal("packarenapart packed wrong amount");
101368c31abSDavid du Colombier 
102368c31abSDavid du Colombier 	return 0;
103368c31abSDavid du Colombier }
104368c31abSDavid du Colombier 
105368c31abSDavid du Colombier int
unpackarena(Arena * arena,u8int * buf)106368c31abSDavid du Colombier unpackarena(Arena *arena, u8int *buf)
107368c31abSDavid du Colombier {
108368c31abSDavid du Colombier 	int sz;
109368c31abSDavid du Colombier 	u8int *p;
110368c31abSDavid du Colombier 	u32int m;
111368c31abSDavid du Colombier 	char fbuf[20];
112368c31abSDavid du Colombier 
113368c31abSDavid du Colombier 	p = buf;
114368c31abSDavid du Colombier 
115368c31abSDavid du Colombier 	m = U32GET(p);
116368c31abSDavid du Colombier 	if(m != ArenaMagic){
117*b8a11165SDavid du Colombier 		seterr(ECorrupt, "arena %d has wrong magic number: %s "
118*b8a11165SDavid du Colombier 			"expected ArenaMagic (%#lux)", debugarena,
119*b8a11165SDavid du Colombier 			fmtmagic(fbuf, m), ArenaMagic);
120368c31abSDavid du Colombier 		return -1;
121368c31abSDavid du Colombier 	}
122368c31abSDavid du Colombier 	p += U32Size;
123368c31abSDavid du Colombier 	arena->version = U32GET(p);
124368c31abSDavid du Colombier 	p += U32Size;
125368c31abSDavid du Colombier 	namecp(arena->name, (char*)p);
126368c31abSDavid du Colombier 	p += ANameSize;
127368c31abSDavid du Colombier 	arena->diskstats.clumps = U32GET(p);
128368c31abSDavid du Colombier 	p += U32Size;
129368c31abSDavid du Colombier 	arena->diskstats.cclumps = U32GET(p);
130368c31abSDavid du Colombier 	p += U32Size;
131368c31abSDavid du Colombier 	arena->ctime = U32GET(p);
132368c31abSDavid du Colombier 	p += U32Size;
133368c31abSDavid du Colombier 	arena->wtime = U32GET(p);
134368c31abSDavid du Colombier 	p += U32Size;
135368c31abSDavid du Colombier 	if(arena->version == ArenaVersion5){
136368c31abSDavid du Colombier 		arena->clumpmagic = U32GET(p);
137368c31abSDavid du Colombier 		p += U32Size;
138368c31abSDavid du Colombier 	}
139368c31abSDavid du Colombier 	arena->diskstats.used = U64GET(p);
140368c31abSDavid du Colombier 	p += U64Size;
141368c31abSDavid du Colombier 	arena->diskstats.uncsize = U64GET(p);
142368c31abSDavid du Colombier 	p += U64Size;
143368c31abSDavid du Colombier 	arena->diskstats.sealed = U8GET(p);
144368c31abSDavid du Colombier 	p += U8Size;
145368c31abSDavid du Colombier 	switch(arena->version){
146368c31abSDavid du Colombier 	case ArenaVersion4:
147368c31abSDavid du Colombier 		sz = ArenaSize4;
148368c31abSDavid du Colombier 		arena->clumpmagic = _ClumpMagic;
149368c31abSDavid du Colombier 		break;
150368c31abSDavid du Colombier 	case ArenaVersion5:
151368c31abSDavid du Colombier 		sz = ArenaSize5;
152368c31abSDavid du Colombier 		break;
153368c31abSDavid du Colombier 	default:
154368c31abSDavid du Colombier 		seterr(ECorrupt, "arena has bad version number %d", arena->version);
155368c31abSDavid du Colombier 		return -1;
156368c31abSDavid du Colombier 	}
157368c31abSDavid du Colombier 	/*
158368c31abSDavid du Colombier 	 * Additional fields for the memstats version of the stats.
159368c31abSDavid du Colombier 	 * Diskstats reflects what is committed to the index.
160368c31abSDavid du Colombier 	 * Memstats reflects what is in the arena.  Originally intended
161368c31abSDavid du Colombier 	 * this to be a version 5 extension, but might as well use for
162368c31abSDavid du Colombier 	 * all the existing version 4 arenas too.
163368c31abSDavid du Colombier 	 *
164368c31abSDavid du Colombier 	 * To maintain backwards compatibility with existing venti
165368c31abSDavid du Colombier 	 * installations using the older format, we define that if
166368c31abSDavid du Colombier 	 * memstats == diskstats, then the extension fields are not
167368c31abSDavid du Colombier 	 * included (see packarena below).  That is, only partially
168368c31abSDavid du Colombier 	 * indexed arenas have these fields.  Fully indexed arenas
169368c31abSDavid du Colombier 	 * (in particular, sealed arenas) do not.
170368c31abSDavid du Colombier 	 */
171368c31abSDavid du Colombier 	if(U8GET(p) == 1){
172368c31abSDavid du Colombier 		sz += ArenaSize5a-ArenaSize5;
173368c31abSDavid du Colombier 		p += U8Size;
174368c31abSDavid du Colombier 		arena->memstats.clumps = U32GET(p);
175368c31abSDavid du Colombier 		p += U32Size;
176368c31abSDavid du Colombier 		arena->memstats.cclumps = U32GET(p);
177368c31abSDavid du Colombier 		p += U32Size;
178368c31abSDavid du Colombier 		arena->memstats.used = U64GET(p);
179368c31abSDavid du Colombier 		p += U64Size;
180368c31abSDavid du Colombier 		arena->memstats.uncsize = U64GET(p);
181368c31abSDavid du Colombier 		p += U64Size;
182368c31abSDavid du Colombier 		arena->memstats.sealed = U8GET(p);
183368c31abSDavid du Colombier 		p += U8Size;
18461f42feeSDavid du Colombier 
18561f42feeSDavid du Colombier 		/*
18661f42feeSDavid du Colombier 		 * 2008/4/2
18761f42feeSDavid du Colombier 		 * Packarena (below) used to have a bug in which it would
18861f42feeSDavid du Colombier 		 * not zero out any existing extension fields when writing
18961f42feeSDavid du Colombier 		 * the arena metadata.  This would manifest itself as arenas
19061f42feeSDavid du Colombier 		 * with arena->diskstats.sealed == 1 but arena->memstats.sealed == 0
19161f42feeSDavid du Colombier 		 * after a server restart.  Because arena->memstats.sealed wouldn't
19261f42feeSDavid du Colombier 		 * be set, the server might try to fit another block into the arena
19361f42feeSDavid du Colombier 		 * (and succeed), violating the append-only structure of the log
19461f42feeSDavid du Colombier 		 * and invalidating any already-computed seal on the arena.
19561f42feeSDavid du Colombier 		 *
19661f42feeSDavid du Colombier 		 * It might end up that other fields in arena->memstats end up
19761f42feeSDavid du Colombier 		 * behind arena->diskstats too, but that would be considerably
19861f42feeSDavid du Colombier 		 * more rare, and the bug is fixed now.  The case we need to
19961f42feeSDavid du Colombier 		 * handle is just the sealed mismatch.
20061f42feeSDavid du Colombier 		 *
20161f42feeSDavid du Colombier 		 * If we encounter such a bogus arena, fix the sealed field.
20261f42feeSDavid du Colombier 		 */
20361f42feeSDavid du Colombier 		if(arena->diskstats.sealed)
20461f42feeSDavid du Colombier 			arena->memstats.sealed = 1;
205368c31abSDavid du Colombier 	}else
206368c31abSDavid du Colombier 		arena->memstats = arena->diskstats;
207368c31abSDavid du Colombier 	if(buf + sz != p)
208368c31abSDavid du Colombier 		sysfatal("unpackarena unpacked wrong amount");
209368c31abSDavid du Colombier 
210368c31abSDavid du Colombier 	return 0;
211368c31abSDavid du Colombier }
212368c31abSDavid du Colombier 
213368c31abSDavid du Colombier int
packarena(Arena * arena,u8int * buf)214368c31abSDavid du Colombier packarena(Arena *arena, u8int *buf)
215368c31abSDavid du Colombier {
216368c31abSDavid du Colombier 	return _packarena(arena, buf, 0);
217368c31abSDavid du Colombier }
218368c31abSDavid du Colombier 
219368c31abSDavid du Colombier int
_packarena(Arena * arena,u8int * buf,int forceext)220368c31abSDavid du Colombier _packarena(Arena *arena, u8int *buf, int forceext)
221368c31abSDavid du Colombier {
222368c31abSDavid du Colombier 	int sz;
223368c31abSDavid du Colombier 	u8int *p;
224368c31abSDavid du Colombier 	u32int t32;
225368c31abSDavid du Colombier 
226368c31abSDavid du Colombier 	switch(arena->version){
227368c31abSDavid du Colombier 	case ArenaVersion4:
228368c31abSDavid du Colombier 		sz = ArenaSize4;
229368c31abSDavid du Colombier 		if(arena->clumpmagic != _ClumpMagic)
230368c31abSDavid du Colombier 			fprint(2, "warning: writing old arena tail loses clump magic 0x%lux != 0x%lux\n",
231368c31abSDavid du Colombier 				(ulong)arena->clumpmagic, (ulong)_ClumpMagic);
232368c31abSDavid du Colombier 		break;
233368c31abSDavid du Colombier 	case ArenaVersion5:
234368c31abSDavid du Colombier 		sz = ArenaSize5;
235368c31abSDavid du Colombier 		break;
236368c31abSDavid du Colombier 	default:
237368c31abSDavid du Colombier 		sysfatal("packarena unknown version %d", arena->version);
238368c31abSDavid du Colombier 		return -1;
239368c31abSDavid du Colombier 	}
240368c31abSDavid du Colombier 
241368c31abSDavid du Colombier 	p = buf;
242368c31abSDavid du Colombier 
243368c31abSDavid du Colombier 	U32PUT(p, ArenaMagic);
244368c31abSDavid du Colombier 	p += U32Size;
245368c31abSDavid du Colombier 	U32PUT(p, arena->version);
246368c31abSDavid du Colombier 	p += U32Size;
247368c31abSDavid du Colombier 	namecp((char*)p, arena->name);
248368c31abSDavid du Colombier 	p += ANameSize;
249368c31abSDavid du Colombier 	U32PUT(p, arena->diskstats.clumps);
250368c31abSDavid du Colombier 	p += U32Size;
251368c31abSDavid du Colombier 	U32PUT(p, arena->diskstats.cclumps);
252368c31abSDavid du Colombier 	p += U32Size;
253368c31abSDavid du Colombier 	U32PUT(p, arena->ctime);
254368c31abSDavid du Colombier 	p += U32Size;
255368c31abSDavid du Colombier 	U32PUT(p, arena->wtime);
256368c31abSDavid du Colombier 	p += U32Size;
257368c31abSDavid du Colombier 	if(arena->version == ArenaVersion5){
258368c31abSDavid du Colombier 		U32PUT(p, arena->clumpmagic);
259368c31abSDavid du Colombier 		p += U32Size;
260368c31abSDavid du Colombier 	}
261368c31abSDavid du Colombier 	U64PUT(p, arena->diskstats.used, t32);
262368c31abSDavid du Colombier 	p += U64Size;
263368c31abSDavid du Colombier 	U64PUT(p, arena->diskstats.uncsize, t32);
264368c31abSDavid du Colombier 	p += U64Size;
265368c31abSDavid du Colombier 	U8PUT(p, arena->diskstats.sealed);
266368c31abSDavid du Colombier 	p += U8Size;
267368c31abSDavid du Colombier 
268368c31abSDavid du Colombier 	/*
269368c31abSDavid du Colombier 	 * Extension fields; see above.
270368c31abSDavid du Colombier 	 */
271368c31abSDavid du Colombier 	if(forceext
272368c31abSDavid du Colombier 	|| arena->memstats.clumps != arena->diskstats.clumps
273368c31abSDavid du Colombier 	|| arena->memstats.cclumps != arena->diskstats.cclumps
274368c31abSDavid du Colombier 	|| arena->memstats.used != arena->diskstats.used
275368c31abSDavid du Colombier 	|| arena->memstats.uncsize != arena->diskstats.uncsize
276368c31abSDavid du Colombier 	|| arena->memstats.sealed != arena->diskstats.sealed){
277368c31abSDavid du Colombier 		sz += ArenaSize5a - ArenaSize5;
278368c31abSDavid du Colombier 		U8PUT(p, 1);
279368c31abSDavid du Colombier 		p += U8Size;
280368c31abSDavid du Colombier 		U32PUT(p, arena->memstats.clumps);
281368c31abSDavid du Colombier 		p += U32Size;
282368c31abSDavid du Colombier 		U32PUT(p, arena->memstats.cclumps);
283368c31abSDavid du Colombier 		p += U32Size;
284368c31abSDavid du Colombier 		U64PUT(p, arena->memstats.used, t32);
285368c31abSDavid du Colombier 		p += U64Size;
286368c31abSDavid du Colombier 		U64PUT(p, arena->memstats.uncsize, t32);
287368c31abSDavid du Colombier 		p += U64Size;
288368c31abSDavid du Colombier 		U8PUT(p, arena->memstats.sealed);
289368c31abSDavid du Colombier 		p += U8Size;
29061f42feeSDavid du Colombier 	}else{
29161f42feeSDavid du Colombier 		/* Clear any extension fields already on disk. */
29261f42feeSDavid du Colombier 		memset(p, 0, ArenaSize5a - ArenaSize5);
29361f42feeSDavid du Colombier 		p += ArenaSize5a - ArenaSize5;
29461f42feeSDavid du Colombier 		sz += ArenaSize5a - ArenaSize5;
295368c31abSDavid du Colombier 	}
296368c31abSDavid du Colombier 
297368c31abSDavid du Colombier 	if(buf + sz != p)
298368c31abSDavid du Colombier 		sysfatal("packarena packed wrong amount");
299368c31abSDavid du Colombier 
300368c31abSDavid du Colombier 	return 0;
301368c31abSDavid du Colombier }
302368c31abSDavid du Colombier 
303368c31abSDavid du Colombier int
unpackarenahead(ArenaHead * head,u8int * buf)304368c31abSDavid du Colombier unpackarenahead(ArenaHead *head, u8int *buf)
305368c31abSDavid du Colombier {
306368c31abSDavid du Colombier 	u8int *p;
307368c31abSDavid du Colombier 	u32int m;
308368c31abSDavid du Colombier 	int sz;
309368c31abSDavid du Colombier 	char fbuf[20];
310368c31abSDavid du Colombier 
311368c31abSDavid du Colombier 	p = buf;
312368c31abSDavid du Colombier 
313368c31abSDavid du Colombier 	m = U32GET(p);
314368c31abSDavid du Colombier 	if(m != ArenaHeadMagic){
315*b8a11165SDavid du Colombier 		seterr(ECorrupt, "arena %d head has wrong magic number: %s "
316*b8a11165SDavid du Colombier 			"expected ArenaHeadMagic (%#lux)", debugarena,
317*b8a11165SDavid du Colombier 			fmtmagic(fbuf, m), ArenaHeadMagic);
318368c31abSDavid du Colombier 		return -1;
319368c31abSDavid du Colombier 	}
320368c31abSDavid du Colombier 
321368c31abSDavid du Colombier 	p += U32Size;
322368c31abSDavid du Colombier 	head->version = U32GET(p);
323368c31abSDavid du Colombier 	p += U32Size;
324368c31abSDavid du Colombier 	namecp(head->name, (char*)p);
325368c31abSDavid du Colombier 	p += ANameSize;
326368c31abSDavid du Colombier 	head->blocksize = U32GET(p);
327368c31abSDavid du Colombier 	p += U32Size;
328368c31abSDavid du Colombier 	head->size = U64GET(p);
329368c31abSDavid du Colombier 	p += U64Size;
330368c31abSDavid du Colombier 	if(head->version == ArenaVersion5){
331368c31abSDavid du Colombier 		head->clumpmagic = U32GET(p);
332368c31abSDavid du Colombier 		p += U32Size;
333368c31abSDavid du Colombier 	}
334368c31abSDavid du Colombier 
335368c31abSDavid du Colombier 	switch(head->version){
336368c31abSDavid du Colombier 	case ArenaVersion4:
337368c31abSDavid du Colombier 		sz = ArenaHeadSize4;
338368c31abSDavid du Colombier 		head->clumpmagic = _ClumpMagic;
339368c31abSDavid du Colombier 		break;
340368c31abSDavid du Colombier 	case ArenaVersion5:
341368c31abSDavid du Colombier 		sz = ArenaHeadSize5;
342368c31abSDavid du Colombier 		break;
343368c31abSDavid du Colombier 	default:
344368c31abSDavid du Colombier 		seterr(ECorrupt, "arena head has unexpected version %d", head->version);
345368c31abSDavid du Colombier 		return -1;
346368c31abSDavid du Colombier 	}
347368c31abSDavid du Colombier 
348368c31abSDavid du Colombier 	if(buf + sz != p)
349368c31abSDavid du Colombier 		sysfatal("unpackarenahead unpacked wrong amount");
350368c31abSDavid du Colombier 
351368c31abSDavid du Colombier 	return 0;
352368c31abSDavid du Colombier }
353368c31abSDavid du Colombier 
354368c31abSDavid du Colombier int
packarenahead(ArenaHead * head,u8int * buf)355368c31abSDavid du Colombier packarenahead(ArenaHead *head, u8int *buf)
356368c31abSDavid du Colombier {
357368c31abSDavid du Colombier 	u8int *p;
358368c31abSDavid du Colombier 	int sz;
359368c31abSDavid du Colombier 	u32int t32;
360368c31abSDavid du Colombier 
361368c31abSDavid du Colombier 	switch(head->version){
362368c31abSDavid du Colombier 	case ArenaVersion4:
363368c31abSDavid du Colombier 		sz = ArenaHeadSize4;
364368c31abSDavid du Colombier 		if(head->clumpmagic != _ClumpMagic)
365368c31abSDavid du Colombier 			fprint(2, "warning: writing old arena header loses clump magic 0x%lux != 0x%lux\n",
366368c31abSDavid du Colombier 				(ulong)head->clumpmagic, (ulong)_ClumpMagic);
367368c31abSDavid du Colombier 		break;
368368c31abSDavid du Colombier 	case ArenaVersion5:
369368c31abSDavid du Colombier 		sz = ArenaHeadSize5;
370368c31abSDavid du Colombier 		break;
371368c31abSDavid du Colombier 	default:
372368c31abSDavid du Colombier 		sysfatal("packarenahead unknown version %d", head->version);
373368c31abSDavid du Colombier 		return -1;
374368c31abSDavid du Colombier 	}
375368c31abSDavid du Colombier 
376368c31abSDavid du Colombier 	p = buf;
377368c31abSDavid du Colombier 
378368c31abSDavid du Colombier 	U32PUT(p, ArenaHeadMagic);
379368c31abSDavid du Colombier 	p += U32Size;
380368c31abSDavid du Colombier 	U32PUT(p, head->version);
381368c31abSDavid du Colombier 	p += U32Size;
382368c31abSDavid du Colombier 	namecp((char*)p, head->name);
383368c31abSDavid du Colombier 	p += ANameSize;
384368c31abSDavid du Colombier 	U32PUT(p, head->blocksize);
385368c31abSDavid du Colombier 	p += U32Size;
386368c31abSDavid du Colombier 	U64PUT(p, head->size, t32);
387368c31abSDavid du Colombier 	p += U64Size;
388368c31abSDavid du Colombier 	if(head->version == ArenaVersion5){
389368c31abSDavid du Colombier 		U32PUT(p, head->clumpmagic);
390368c31abSDavid du Colombier 		p += U32Size;
391368c31abSDavid du Colombier 	}
392368c31abSDavid du Colombier 	if(buf + sz != p)
393368c31abSDavid du Colombier 		sysfatal("packarenahead packed wrong amount");
394368c31abSDavid du Colombier 
395368c31abSDavid du Colombier 	return 0;
396368c31abSDavid du Colombier }
397368c31abSDavid du Colombier 
398368c31abSDavid du Colombier static int
checkclump(Clump * w)399368c31abSDavid du Colombier checkclump(Clump *w)
400368c31abSDavid du Colombier {
401368c31abSDavid du Colombier 	if(w->encoding == ClumpENone){
402368c31abSDavid du Colombier 		if(w->info.size != w->info.uncsize){
403368c31abSDavid du Colombier 			seterr(ECorrupt, "uncompressed wad size mismatch");
404368c31abSDavid du Colombier 			return -1;
405368c31abSDavid du Colombier 		}
406368c31abSDavid du Colombier 	}else if(w->encoding == ClumpECompress){
407368c31abSDavid du Colombier 		if(w->info.size >= w->info.uncsize){
408368c31abSDavid du Colombier 			seterr(ECorrupt, "compressed lump has inconsistent block sizes %d %d", w->info.size, w->info.uncsize);
409368c31abSDavid du Colombier 			return -1;
410368c31abSDavid du Colombier 		}
411368c31abSDavid du Colombier 	}else{
412368c31abSDavid du Colombier 		seterr(ECorrupt, "clump has illegal encoding");
413368c31abSDavid du Colombier 		return -1;
414368c31abSDavid du Colombier 	}
415368c31abSDavid du Colombier 
416368c31abSDavid du Colombier 	return 0;
417368c31abSDavid du Colombier }
418368c31abSDavid du Colombier 
419368c31abSDavid du Colombier int
unpackclump(Clump * c,u8int * buf,u32int cmagic)420368c31abSDavid du Colombier unpackclump(Clump *c, u8int *buf, u32int cmagic)
421368c31abSDavid du Colombier {
422368c31abSDavid du Colombier 	u8int *p;
423368c31abSDavid du Colombier 	u32int magic;
424368c31abSDavid du Colombier 
425368c31abSDavid du Colombier 	p = buf;
426368c31abSDavid du Colombier 	magic = U32GET(p);
427368c31abSDavid du Colombier 	if(magic != cmagic){
428368c31abSDavid du Colombier 		seterr(ECorrupt, "clump has bad magic number=%#8.8ux != %#8.8ux", magic, cmagic);
429368c31abSDavid du Colombier 		return -1;
430368c31abSDavid du Colombier 	}
431368c31abSDavid du Colombier 	p += U32Size;
432368c31abSDavid du Colombier 
433368c31abSDavid du Colombier 	c->info.type = vtfromdisktype(U8GET(p));
434368c31abSDavid du Colombier 	p += U8Size;
435368c31abSDavid du Colombier 	c->info.size = U16GET(p);
436368c31abSDavid du Colombier 	p += U16Size;
437368c31abSDavid du Colombier 	c->info.uncsize = U16GET(p);
438368c31abSDavid du Colombier 	p += U16Size;
439368c31abSDavid du Colombier 	scorecp(c->info.score, p);
440368c31abSDavid du Colombier 	p += VtScoreSize;
441368c31abSDavid du Colombier 
442368c31abSDavid du Colombier 	c->encoding = U8GET(p);
443368c31abSDavid du Colombier 	p += U8Size;
444368c31abSDavid du Colombier 	c->creator = U32GET(p);
445368c31abSDavid du Colombier 	p += U32Size;
446368c31abSDavid du Colombier 	c->time = U32GET(p);
447368c31abSDavid du Colombier 	p += U32Size;
448368c31abSDavid du Colombier 
449368c31abSDavid du Colombier 	if(buf + ClumpSize != p)
450368c31abSDavid du Colombier 		sysfatal("unpackclump unpacked wrong amount");
451368c31abSDavid du Colombier 
452368c31abSDavid du Colombier 	return checkclump(c);
453368c31abSDavid du Colombier }
454368c31abSDavid du Colombier 
455368c31abSDavid du Colombier int
packclump(Clump * c,u8int * buf,u32int magic)456368c31abSDavid du Colombier packclump(Clump *c, u8int *buf, u32int magic)
457368c31abSDavid du Colombier {
458368c31abSDavid du Colombier 	u8int *p;
459368c31abSDavid du Colombier 
460368c31abSDavid du Colombier 	p = buf;
461368c31abSDavid du Colombier 	U32PUT(p, magic);
462368c31abSDavid du Colombier 	p += U32Size;
463368c31abSDavid du Colombier 
464368c31abSDavid du Colombier 	U8PUT(p, vttodisktype(c->info.type));
465368c31abSDavid du Colombier 	p += U8Size;
466368c31abSDavid du Colombier 	U16PUT(p, c->info.size);
467368c31abSDavid du Colombier 	p += U16Size;
468368c31abSDavid du Colombier 	U16PUT(p, c->info.uncsize);
469368c31abSDavid du Colombier 	p += U16Size;
470368c31abSDavid du Colombier 	scorecp(p, c->info.score);
471368c31abSDavid du Colombier 	p += VtScoreSize;
472368c31abSDavid du Colombier 
473368c31abSDavid du Colombier 	U8PUT(p, c->encoding);
474368c31abSDavid du Colombier 	p += U8Size;
475368c31abSDavid du Colombier 	U32PUT(p, c->creator);
476368c31abSDavid du Colombier 	p += U32Size;
477368c31abSDavid du Colombier 	U32PUT(p, c->time);
478368c31abSDavid du Colombier 	p += U32Size;
479368c31abSDavid du Colombier 
480368c31abSDavid du Colombier 	if(buf + ClumpSize != p)
481368c31abSDavid du Colombier 		sysfatal("packclump packed wrong amount");
482368c31abSDavid du Colombier 
483368c31abSDavid du Colombier 	return checkclump(c);
484368c31abSDavid du Colombier }
485368c31abSDavid du Colombier 
486368c31abSDavid du Colombier void
unpackclumpinfo(ClumpInfo * ci,u8int * buf)487368c31abSDavid du Colombier unpackclumpinfo(ClumpInfo *ci, u8int *buf)
488368c31abSDavid du Colombier {
489368c31abSDavid du Colombier 	u8int *p;
490368c31abSDavid du Colombier 
491368c31abSDavid du Colombier 	p = buf;
492368c31abSDavid du Colombier 	ci->type = vtfromdisktype(U8GET(p));
493368c31abSDavid du Colombier 	p += U8Size;
494368c31abSDavid du Colombier 	ci->size = U16GET(p);
495368c31abSDavid du Colombier 	p += U16Size;
496368c31abSDavid du Colombier 	ci->uncsize = U16GET(p);
497368c31abSDavid du Colombier 	p += U16Size;
498368c31abSDavid du Colombier 	scorecp(ci->score, p);
499368c31abSDavid du Colombier 	p += VtScoreSize;
500368c31abSDavid du Colombier 
501368c31abSDavid du Colombier 	if(buf + ClumpInfoSize != p)
502368c31abSDavid du Colombier 		sysfatal("unpackclumpinfo unpacked wrong amount");
503368c31abSDavid du Colombier }
504368c31abSDavid du Colombier 
505368c31abSDavid du Colombier void
packclumpinfo(ClumpInfo * ci,u8int * buf)506368c31abSDavid du Colombier packclumpinfo(ClumpInfo *ci, u8int *buf)
507368c31abSDavid du Colombier {
508368c31abSDavid du Colombier 	u8int *p;
509368c31abSDavid du Colombier 
510368c31abSDavid du Colombier 	p = buf;
511368c31abSDavid du Colombier 	U8PUT(p, vttodisktype(ci->type));
512368c31abSDavid du Colombier 	p += U8Size;
513368c31abSDavid du Colombier 	U16PUT(p, ci->size);
514368c31abSDavid du Colombier 	p += U16Size;
515368c31abSDavid du Colombier 	U16PUT(p, ci->uncsize);
516368c31abSDavid du Colombier 	p += U16Size;
517368c31abSDavid du Colombier 	scorecp(p, ci->score);
518368c31abSDavid du Colombier 	p += VtScoreSize;
519368c31abSDavid du Colombier 
520368c31abSDavid du Colombier 	if(buf + ClumpInfoSize != p)
521368c31abSDavid du Colombier 		sysfatal("packclumpinfo packed wrong amount");
522368c31abSDavid du Colombier }
523368c31abSDavid du Colombier 
524368c31abSDavid du Colombier int
unpackisect(ISect * is,u8int * buf)525368c31abSDavid du Colombier unpackisect(ISect *is, u8int *buf)
526368c31abSDavid du Colombier {
527368c31abSDavid du Colombier 	u8int *p;
528368c31abSDavid du Colombier 	u32int m;
529368c31abSDavid du Colombier 	char fbuf[20];
530368c31abSDavid du Colombier 
531368c31abSDavid du Colombier 	p = buf;
532368c31abSDavid du Colombier 
533368c31abSDavid du Colombier 
534368c31abSDavid du Colombier 	m = U32GET(p);
535368c31abSDavid du Colombier 	if(m != ISectMagic){
536368c31abSDavid du Colombier 		seterr(ECorrupt, "index section has wrong magic number: %s expected ISectMagic (%#lux)",
537368c31abSDavid du Colombier 			fmtmagic(fbuf, m), ISectMagic);
538368c31abSDavid du Colombier 		return -1;
539368c31abSDavid du Colombier 	}
540368c31abSDavid du Colombier 	p += U32Size;
541368c31abSDavid du Colombier 	is->version = U32GET(p);
542368c31abSDavid du Colombier 	p += U32Size;
543368c31abSDavid du Colombier 	namecp(is->name, (char*)p);
544368c31abSDavid du Colombier 	p += ANameSize;
545368c31abSDavid du Colombier 	namecp(is->index, (char*)p);
546368c31abSDavid du Colombier 	p += ANameSize;
547368c31abSDavid du Colombier 	is->blocksize = U32GET(p);
548368c31abSDavid du Colombier 	p += U32Size;
549368c31abSDavid du Colombier 	is->blockbase = U32GET(p);
550368c31abSDavid du Colombier 	p += U32Size;
551368c31abSDavid du Colombier 	is->blocks = U32GET(p);
552368c31abSDavid du Colombier 	p += U32Size;
553368c31abSDavid du Colombier 	is->start = U32GET(p);
554368c31abSDavid du Colombier 	p += U32Size;
555368c31abSDavid du Colombier 	is->stop = U32GET(p);
556368c31abSDavid du Colombier 	p += U32Size;
557368c31abSDavid du Colombier 	if(buf + ISectSize1 != p)
558368c31abSDavid du Colombier 		sysfatal("unpackisect unpacked wrong amount");
559368c31abSDavid du Colombier 	is->bucketmagic = 0;
560368c31abSDavid du Colombier 	if(is->version == ISectVersion2){
561368c31abSDavid du Colombier 		is->bucketmagic = U32GET(p);
562368c31abSDavid du Colombier 		p += U32Size;
563368c31abSDavid du Colombier 		if(buf + ISectSize2 != p)
564368c31abSDavid du Colombier 			sysfatal("unpackisect unpacked wrong amount");
565368c31abSDavid du Colombier 	}
566368c31abSDavid du Colombier 
567368c31abSDavid du Colombier 	return 0;
568368c31abSDavid du Colombier }
569368c31abSDavid du Colombier 
570368c31abSDavid du Colombier int
packisect(ISect * is,u8int * buf)571368c31abSDavid du Colombier packisect(ISect *is, u8int *buf)
572368c31abSDavid du Colombier {
573368c31abSDavid du Colombier 	u8int *p;
574368c31abSDavid du Colombier 
575368c31abSDavid du Colombier 	p = buf;
576368c31abSDavid du Colombier 
577368c31abSDavid du Colombier 	U32PUT(p, ISectMagic);
578368c31abSDavid du Colombier 	p += U32Size;
579368c31abSDavid du Colombier 	U32PUT(p, is->version);
580368c31abSDavid du Colombier 	p += U32Size;
581368c31abSDavid du Colombier 	namecp((char*)p, is->name);
582368c31abSDavid du Colombier 	p += ANameSize;
583368c31abSDavid du Colombier 	namecp((char*)p, is->index);
584368c31abSDavid du Colombier 	p += ANameSize;
585368c31abSDavid du Colombier 	U32PUT(p, is->blocksize);
586368c31abSDavid du Colombier 	p += U32Size;
587368c31abSDavid du Colombier 	U32PUT(p, is->blockbase);
588368c31abSDavid du Colombier 	p += U32Size;
589368c31abSDavid du Colombier 	U32PUT(p, is->blocks);
590368c31abSDavid du Colombier 	p += U32Size;
591368c31abSDavid du Colombier 	U32PUT(p, is->start);
592368c31abSDavid du Colombier 	p += U32Size;
593368c31abSDavid du Colombier 	U32PUT(p, is->stop);
594368c31abSDavid du Colombier 	p += U32Size;
595368c31abSDavid du Colombier 	if(buf + ISectSize1 != p)
596368c31abSDavid du Colombier 		sysfatal("packisect packed wrong amount");
597368c31abSDavid du Colombier 	if(is->version == ISectVersion2){
598368c31abSDavid du Colombier 		U32PUT(p, is->bucketmagic);
599368c31abSDavid du Colombier 		p += U32Size;
600368c31abSDavid du Colombier 		if(buf + ISectSize2 != p)
601368c31abSDavid du Colombier 			sysfatal("packisect packed wrong amount");
602368c31abSDavid du Colombier 	}
603368c31abSDavid du Colombier 
604368c31abSDavid du Colombier 	return 0;
605368c31abSDavid du Colombier }
606368c31abSDavid du Colombier 
607368c31abSDavid du Colombier void
unpackientry(IEntry * ie,u8int * buf)608368c31abSDavid du Colombier unpackientry(IEntry *ie, u8int *buf)
609368c31abSDavid du Colombier {
610368c31abSDavid du Colombier 	u8int *p;
611368c31abSDavid du Colombier 
612368c31abSDavid du Colombier 	p = buf;
613368c31abSDavid du Colombier 
614368c31abSDavid du Colombier 	scorecp(ie->score, p);
615368c31abSDavid du Colombier 	p += VtScoreSize;
616f9e1cf08SDavid du Colombier 	/* ie->wtime = U32GET(p); */
617368c31abSDavid du Colombier 	p += U32Size;
618f9e1cf08SDavid du Colombier 	/* ie->train = U16GET(p); */
619368c31abSDavid du Colombier 	p += U16Size;
620368c31abSDavid du Colombier 	if(p - buf != IEntryAddrOff)
621368c31abSDavid du Colombier 		sysfatal("unpackentry bad IEntryAddrOff amount");
622368c31abSDavid du Colombier 	ie->ia.addr = U64GET(p);
623368c31abSDavid du Colombier if(ie->ia.addr>>56) print("%.8H => %llux\n", p, ie->ia.addr);
624368c31abSDavid du Colombier 	p += U64Size;
625368c31abSDavid du Colombier 	ie->ia.size = U16GET(p);
626368c31abSDavid du Colombier 	p += U16Size;
627368c31abSDavid du Colombier 	if(p - buf != IEntryTypeOff)
628368c31abSDavid du Colombier 		sysfatal("unpackientry bad IEntryTypeOff amount");
629368c31abSDavid du Colombier 	ie->ia.type = vtfromdisktype(U8GET(p));
630368c31abSDavid du Colombier 	p += U8Size;
631368c31abSDavid du Colombier 	ie->ia.blocks = U8GET(p);
632368c31abSDavid du Colombier 	p += U8Size;
633368c31abSDavid du Colombier 
634368c31abSDavid du Colombier 	if(p - buf != IEntrySize)
635368c31abSDavid du Colombier 		sysfatal("unpackientry unpacked wrong amount");
636368c31abSDavid du Colombier }
637368c31abSDavid du Colombier 
638368c31abSDavid du Colombier void
packientry(IEntry * ie,u8int * buf)639368c31abSDavid du Colombier packientry(IEntry *ie, u8int *buf)
640368c31abSDavid du Colombier {
641368c31abSDavid du Colombier 	u32int t32;
642368c31abSDavid du Colombier 	u8int *p;
643368c31abSDavid du Colombier 
644368c31abSDavid du Colombier 	p = buf;
645368c31abSDavid du Colombier 
646368c31abSDavid du Colombier 	scorecp(p, ie->score);
647368c31abSDavid du Colombier 	p += VtScoreSize;
648f9e1cf08SDavid du Colombier 	U32PUT(p, 0); /* wtime */
649368c31abSDavid du Colombier 	p += U32Size;
650f9e1cf08SDavid du Colombier 	U16PUT(p, 0); /* train */
651368c31abSDavid du Colombier 	p += U16Size;
652368c31abSDavid du Colombier 	U64PUT(p, ie->ia.addr, t32);
653368c31abSDavid du Colombier 	p += U64Size;
654368c31abSDavid du Colombier 	U16PUT(p, ie->ia.size);
655368c31abSDavid du Colombier 	p += U16Size;
656368c31abSDavid du Colombier 	U8PUT(p, vttodisktype(ie->ia.type));
657368c31abSDavid du Colombier 	p += U8Size;
658368c31abSDavid du Colombier 	U8PUT(p, ie->ia.blocks);
659368c31abSDavid du Colombier 	p += U8Size;
660368c31abSDavid du Colombier 
661368c31abSDavid du Colombier 	if(p - buf != IEntrySize)
662368c31abSDavid du Colombier 		sysfatal("packientry packed wrong amount");
663368c31abSDavid du Colombier }
664368c31abSDavid du Colombier 
665368c31abSDavid du Colombier void
unpackibucket(IBucket * b,u8int * buf,u32int magic)666368c31abSDavid du Colombier unpackibucket(IBucket *b, u8int *buf, u32int magic)
667368c31abSDavid du Colombier {
668368c31abSDavid du Colombier 	b->n = U16GET(buf);
669368c31abSDavid du Colombier 	b->data = buf + IBucketSize;
670368c31abSDavid du Colombier 	if(magic && magic != U32GET(buf+U16Size))
671368c31abSDavid du Colombier 		b->n = 0;
672368c31abSDavid du Colombier }
673368c31abSDavid du Colombier 
674368c31abSDavid du Colombier void
packibucket(IBucket * b,u8int * buf,u32int magic)675368c31abSDavid du Colombier packibucket(IBucket *b, u8int *buf, u32int magic)
676368c31abSDavid du Colombier {
677368c31abSDavid du Colombier 	U16PUT(buf, b->n);
678368c31abSDavid du Colombier 	U32PUT(buf+U16Size, magic);
679368c31abSDavid du Colombier }
680368c31abSDavid du Colombier 
681368c31abSDavid du Colombier void
packbloomhead(Bloom * b,u8int * buf)682368c31abSDavid du Colombier packbloomhead(Bloom *b, u8int *buf)
683368c31abSDavid du Colombier {
684368c31abSDavid du Colombier 	u8int *p;
685368c31abSDavid du Colombier 
686368c31abSDavid du Colombier 	p = buf;
687368c31abSDavid du Colombier 	U32PUT(p, BloomMagic);
688368c31abSDavid du Colombier 	U32PUT(p+4, BloomVersion);
689368c31abSDavid du Colombier 	U32PUT(p+8, b->nhash);
690368c31abSDavid du Colombier 	U32PUT(p+12, b->size);
691368c31abSDavid du Colombier }
692368c31abSDavid du Colombier 
693368c31abSDavid du Colombier int
unpackbloomhead(Bloom * b,u8int * buf)694368c31abSDavid du Colombier unpackbloomhead(Bloom *b, u8int *buf)
695368c31abSDavid du Colombier {
696368c31abSDavid du Colombier 	u8int *p;
697368c31abSDavid du Colombier 	u32int m;
698368c31abSDavid du Colombier 	char fbuf[20];
699368c31abSDavid du Colombier 
700368c31abSDavid du Colombier 	p = buf;
701368c31abSDavid du Colombier 
702368c31abSDavid du Colombier 	m = U32GET(p);
703368c31abSDavid du Colombier 	if(m != BloomMagic){
704368c31abSDavid du Colombier 		seterr(ECorrupt, "bloom filter has wrong magic number: %s expected BloomMagic (%#lux)", fmtmagic(fbuf, m), (ulong)BloomMagic);
705368c31abSDavid du Colombier 		return -1;
706368c31abSDavid du Colombier 	}
707368c31abSDavid du Colombier 	p += U32Size;
708368c31abSDavid du Colombier 
709368c31abSDavid du Colombier 	m = U32GET(p);
710368c31abSDavid du Colombier 	if(m != BloomVersion){
711368c31abSDavid du Colombier 		seterr(ECorrupt, "bloom filter has wrong version %ud expected %ud", (uint)m, (uint)BloomVersion);
712368c31abSDavid du Colombier 		return -1;
713368c31abSDavid du Colombier 	}
714368c31abSDavid du Colombier 	p += U32Size;
715368c31abSDavid du Colombier 
716368c31abSDavid du Colombier 	b->nhash = U32GET(p);
717368c31abSDavid du Colombier 	p += U32Size;
718368c31abSDavid du Colombier 
719368c31abSDavid du Colombier 	b->size = U32GET(p);
720368c31abSDavid du Colombier 	p += U32Size;
721368c31abSDavid du Colombier 	if(b->size < BloomHeadSize || b->size > MaxBloomSize || (b->size&(b->size-1))){
722368c31abSDavid du Colombier 		seterr(ECorrupt, "bloom filter has invalid size %#lux", b->size);
723368c31abSDavid du Colombier 		return -1;
724368c31abSDavid du Colombier 	}
725368c31abSDavid du Colombier 
726368c31abSDavid du Colombier 	if(buf + BloomHeadSize != p)
727368c31abSDavid du Colombier 		sysfatal("unpackarena unpacked wrong amount");
728368c31abSDavid du Colombier 
729368c31abSDavid du Colombier 	return 0;
730368c31abSDavid du Colombier }
731