plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

conv.c (15267B)


      1 #include "stdinc.h"
      2 #include "dat.h"
      3 #include "fns.h"
      4 
      5 /*
      6  * disk structure conversion routines
      7  */
      8 #define	U8GET(p)	((p)[0])
      9 #define	U16GET(p)	(((p)[0]<<8)|(p)[1])
     10 #define	U32GET(p)	((u32int)(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3]))
     11 #define	U64GET(p)	(((u64int)U32GET(p)<<32)|(u64int)U32GET((p)+4))
     12 
     13 #define	U8PUT(p,v)	(p)[0]=(v)&0xFF
     14 #define	U16PUT(p,v)	(p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF
     15 #define	U32PUT(p,v)	(p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF
     16 #define	U64PUT(p,v,t32)	t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
     17 
     18 int debugarena = -1;		/* hack to improve error reporting */
     19 
     20 static struct {
     21 	u32int m;
     22 	char *s;
     23 } magics[] = {
     24 	ArenaPartMagic, "ArenaPartMagic",
     25 	ArenaHeadMagic, "ArenaHeadMagic",
     26 	ArenaMagic, "ArenaMagic",
     27 	ISectMagic, "ISectMagic",
     28 	BloomMagic, "BloomMagic",
     29 };
     30 
     31 static char*
     32 fmtmagic(char *s, u32int m)
     33 {
     34 	int i;
     35 
     36 	for(i=0; i<nelem(magics); i++)
     37 		if(magics[i].m == m)
     38 			return magics[i].s;
     39 	sprint(s, "%#08ux", m);
     40 	return s;
     41 }
     42 
     43 u32int
     44 unpackmagic(u8int *buf)
     45 {
     46 	return U32GET(buf);
     47 }
     48 
     49 void
     50 packmagic(u32int magic, u8int *buf)
     51 {
     52 	U32PUT(buf, magic);
     53 }
     54 
     55 int
     56 unpackarenapart(ArenaPart *ap, u8int *buf)
     57 {
     58 	u8int *p;
     59 	u32int m;
     60 	char fbuf[20];
     61 
     62 	p = buf;
     63 
     64 	m = U32GET(p);
     65 	if(m != ArenaPartMagic){
     66 		seterr(ECorrupt, "arena set has wrong magic number: %s expected ArenaPartMagic (%#lux)", fmtmagic(fbuf, m), ArenaPartMagic);
     67 		return -1;
     68 	}
     69 	p += U32Size;
     70 	ap->version = U32GET(p);
     71 	p += U32Size;
     72 	ap->blocksize = U32GET(p);
     73 	p += U32Size;
     74 	ap->arenabase = U32GET(p);
     75 	p += U32Size;
     76 
     77 	if(buf + ArenaPartSize != p)
     78 		sysfatal("unpackarenapart unpacked wrong amount");
     79 
     80 	return 0;
     81 }
     82 
     83 int
     84 packarenapart(ArenaPart *ap, u8int *buf)
     85 {
     86 	u8int *p;
     87 
     88 	p = buf;
     89 
     90 	U32PUT(p, ArenaPartMagic);
     91 	p += U32Size;
     92 	U32PUT(p, ap->version);
     93 	p += U32Size;
     94 	U32PUT(p, ap->blocksize);
     95 	p += U32Size;
     96 	U32PUT(p, ap->arenabase);
     97 	p += U32Size;
     98 
     99 	if(buf + ArenaPartSize != p)
    100 		sysfatal("packarenapart packed wrong amount");
    101 
    102 	return 0;
    103 }
    104 
    105 int
    106 unpackarena(Arena *arena, u8int *buf)
    107 {
    108 	int sz;
    109 	u8int *p;
    110 	u32int m;
    111 	char fbuf[20];
    112 
    113 	p = buf;
    114 
    115 	m = U32GET(p);
    116 	if(m != ArenaMagic){
    117 		seterr(ECorrupt, "arena %d has wrong magic number: %s "
    118 			"expected ArenaMagic (%#lux)", debugarena,
    119 			fmtmagic(fbuf, m), ArenaMagic);
    120 		return -1;
    121 	}
    122 	p += U32Size;
    123 	arena->version = U32GET(p);
    124 	p += U32Size;
    125 	namecp(arena->name, (char*)p);
    126 	p += ANameSize;
    127 	arena->diskstats.clumps = U32GET(p);
    128 	p += U32Size;
    129 	arena->diskstats.cclumps = U32GET(p);
    130 	p += U32Size;
    131 	arena->ctime = U32GET(p);
    132 	p += U32Size;
    133 	arena->wtime = U32GET(p);
    134 	p += U32Size;
    135 	if(arena->version == ArenaVersion5){
    136 		arena->clumpmagic = U32GET(p);
    137 		p += U32Size;
    138 	}
    139 	arena->diskstats.used = U64GET(p);
    140 	p += U64Size;
    141 	arena->diskstats.uncsize = U64GET(p);
    142 	p += U64Size;
    143 	arena->diskstats.sealed = U8GET(p);
    144 	p += U8Size;
    145 	switch(arena->version){
    146 	case ArenaVersion4:
    147 		sz = ArenaSize4;
    148 		arena->clumpmagic = _ClumpMagic;
    149 		break;
    150 	case ArenaVersion5:
    151 		sz = ArenaSize5;
    152 		break;
    153 	default:
    154 		seterr(ECorrupt, "arena has bad version number %d", arena->version);
    155 		return -1;
    156 	}
    157 	/*
    158 	 * Additional fields for the memstats version of the stats.
    159 	 * Diskstats reflects what is committed to the index.
    160 	 * Memstats reflects what is in the arena.  Originally intended
    161 	 * this to be a version 5 extension, but might as well use for
    162 	 * all the existing version 4 arenas too.
    163 	 *
    164 	 * To maintain backwards compatibility with existing venti
    165 	 * installations using the older format, we define that if
    166 	 * memstats == diskstats, then the extension fields are not
    167 	 * included (see packarena below).  That is, only partially
    168 	 * indexed arenas have these fields.  Fully indexed arenas
    169 	 * (in particular, sealed arenas) do not.
    170 	 */
    171 	if(U8GET(p) == 1){
    172 		sz += ArenaSize5a-ArenaSize5;
    173 		p += U8Size;
    174 		arena->memstats.clumps = U32GET(p);
    175 		p += U32Size;
    176 		arena->memstats.cclumps = U32GET(p);
    177 		p += U32Size;
    178 		arena->memstats.used = U64GET(p);
    179 		p += U64Size;
    180 		arena->memstats.uncsize = U64GET(p);
    181 		p += U64Size;
    182 		arena->memstats.sealed = U8GET(p);
    183 		p += U8Size;
    184 
    185 		/*
    186 		 * 2008/4/2
    187 		 * Packarena (below) used to have a bug in which it would
    188 		 * not zero out any existing extension fields when writing
    189 		 * the arena metadata.  This would manifest itself as arenas
    190 		 * with arena->diskstats.sealed == 1 but arena->memstats.sealed == 0
    191 		 * after a server restart.  Because arena->memstats.sealed wouldn't
    192 		 * be set, the server might try to fit another block into the arena
    193 		 * (and succeed), violating the append-only structure of the log
    194 		 * and invalidating any already-computed seal on the arena.
    195 		 *
    196 		 * It might end up that other fields in arena->memstats end up
    197 		 * behind arena->diskstats too, but that would be considerably
    198 		 * more rare, and the bug is fixed now.  The case we need to
    199 		 * handle is just the sealed mismatch.
    200 		 *
    201 		 * If we encounter such a bogus arena, fix the sealed field.
    202 		 */
    203 		if(arena->diskstats.sealed)
    204 			arena->memstats.sealed = 1;
    205 	}else
    206 		arena->memstats = arena->diskstats;
    207 	if(buf + sz != p)
    208 		sysfatal("unpackarena unpacked wrong amount");
    209 
    210 	return 0;
    211 }
    212 
    213 int
    214 packarena(Arena *arena, u8int *buf)
    215 {
    216 	return _packarena(arena, buf, 0);
    217 }
    218 
    219 int
    220 _packarena(Arena *arena, u8int *buf, int forceext)
    221 {
    222 	int sz;
    223 	u8int *p;
    224 	u32int t32;
    225 
    226 	switch(arena->version){
    227 	case ArenaVersion4:
    228 		sz = ArenaSize4;
    229 		if(arena->clumpmagic != _ClumpMagic)
    230 			fprint(2, "warning: writing old arena tail loses clump magic 0x%lux != 0x%lux\n",
    231 				(ulong)arena->clumpmagic, (ulong)_ClumpMagic);
    232 		break;
    233 	case ArenaVersion5:
    234 		sz = ArenaSize5;
    235 		break;
    236 	default:
    237 		sysfatal("packarena unknown version %d", arena->version);
    238 		return -1;
    239 	}
    240 
    241 	p = buf;
    242 
    243 	U32PUT(p, ArenaMagic);
    244 	p += U32Size;
    245 	U32PUT(p, arena->version);
    246 	p += U32Size;
    247 	namecp((char*)p, arena->name);
    248 	p += ANameSize;
    249 	U32PUT(p, arena->diskstats.clumps);
    250 	p += U32Size;
    251 	U32PUT(p, arena->diskstats.cclumps);
    252 	p += U32Size;
    253 	U32PUT(p, arena->ctime);
    254 	p += U32Size;
    255 	U32PUT(p, arena->wtime);
    256 	p += U32Size;
    257 	if(arena->version == ArenaVersion5){
    258 		U32PUT(p, arena->clumpmagic);
    259 		p += U32Size;
    260 	}
    261 	U64PUT(p, arena->diskstats.used, t32);
    262 	p += U64Size;
    263 	U64PUT(p, arena->diskstats.uncsize, t32);
    264 	p += U64Size;
    265 	U8PUT(p, arena->diskstats.sealed);
    266 	p += U8Size;
    267 
    268 	/*
    269 	 * Extension fields; see above.
    270 	 */
    271 	if(forceext
    272 	|| arena->memstats.clumps != arena->diskstats.clumps
    273 	|| arena->memstats.cclumps != arena->diskstats.cclumps
    274 	|| arena->memstats.used != arena->diskstats.used
    275 	|| arena->memstats.uncsize != arena->diskstats.uncsize
    276 	|| arena->memstats.sealed != arena->diskstats.sealed){
    277 		sz += ArenaSize5a - ArenaSize5;
    278 		U8PUT(p, 1);
    279 		p += U8Size;
    280 		U32PUT(p, arena->memstats.clumps);
    281 		p += U32Size;
    282 		U32PUT(p, arena->memstats.cclumps);
    283 		p += U32Size;
    284 		U64PUT(p, arena->memstats.used, t32);
    285 		p += U64Size;
    286 		U64PUT(p, arena->memstats.uncsize, t32);
    287 		p += U64Size;
    288 		U8PUT(p, arena->memstats.sealed);
    289 		p += U8Size;
    290 	}else{
    291 		/* Clear any extension fields already on disk. */
    292 		memset(p, 0, ArenaSize5a - ArenaSize5);
    293 		p += ArenaSize5a - ArenaSize5;
    294 		sz += ArenaSize5a - ArenaSize5;
    295 	}
    296 
    297 	if(buf + sz != p)
    298 		sysfatal("packarena packed wrong amount");
    299 
    300 	return 0;
    301 }
    302 
    303 int
    304 unpackarenahead(ArenaHead *head, u8int *buf)
    305 {
    306 	u8int *p;
    307 	u32int m;
    308 	int sz;
    309 	char fbuf[20];
    310 
    311 	p = buf;
    312 
    313 	m = U32GET(p);
    314 	if(m != ArenaHeadMagic){
    315 		seterr(ECorrupt, "arena %d head has wrong magic number: %s "
    316 			"expected ArenaHeadMagic (%#lux)", debugarena,
    317 			fmtmagic(fbuf, m), ArenaHeadMagic);
    318 		return -1;
    319 	}
    320 
    321 	p += U32Size;
    322 	head->version = U32GET(p);
    323 	p += U32Size;
    324 	namecp(head->name, (char*)p);
    325 	p += ANameSize;
    326 	head->blocksize = U32GET(p);
    327 	p += U32Size;
    328 	head->size = U64GET(p);
    329 	p += U64Size;
    330 	if(head->version == ArenaVersion5){
    331 		head->clumpmagic = U32GET(p);
    332 		p += U32Size;
    333 	}
    334 
    335 	switch(head->version){
    336 	case ArenaVersion4:
    337 		sz = ArenaHeadSize4;
    338 		head->clumpmagic = _ClumpMagic;
    339 		break;
    340 	case ArenaVersion5:
    341 		sz = ArenaHeadSize5;
    342 		break;
    343 	default:
    344 		seterr(ECorrupt, "arena head has unexpected version %d", head->version);
    345 		return -1;
    346 	}
    347 
    348 	if(buf + sz != p)
    349 		sysfatal("unpackarenahead unpacked wrong amount");
    350 
    351 	return 0;
    352 }
    353 
    354 int
    355 packarenahead(ArenaHead *head, u8int *buf)
    356 {
    357 	u8int *p;
    358 	int sz;
    359 	u32int t32;
    360 
    361 	switch(head->version){
    362 	case ArenaVersion4:
    363 		sz = ArenaHeadSize4;
    364 		if(head->clumpmagic != _ClumpMagic)
    365 			fprint(2, "warning: writing old arena header loses clump magic 0x%lux != 0x%lux\n",
    366 				(ulong)head->clumpmagic, (ulong)_ClumpMagic);
    367 		break;
    368 	case ArenaVersion5:
    369 		sz = ArenaHeadSize5;
    370 		break;
    371 	default:
    372 		sysfatal("packarenahead unknown version %d", head->version);
    373 		return -1;
    374 	}
    375 
    376 	p = buf;
    377 
    378 	U32PUT(p, ArenaHeadMagic);
    379 	p += U32Size;
    380 	U32PUT(p, head->version);
    381 	p += U32Size;
    382 	namecp((char*)p, head->name);
    383 	p += ANameSize;
    384 	U32PUT(p, head->blocksize);
    385 	p += U32Size;
    386 	U64PUT(p, head->size, t32);
    387 	p += U64Size;
    388 	if(head->version == ArenaVersion5){
    389 		U32PUT(p, head->clumpmagic);
    390 		p += U32Size;
    391 	}
    392 	if(buf + sz != p)
    393 		sysfatal("packarenahead packed wrong amount");
    394 
    395 	return 0;
    396 }
    397 
    398 static int
    399 checkclump(Clump *w)
    400 {
    401 	if(w->encoding == ClumpENone){
    402 		if(w->info.size != w->info.uncsize){
    403 			seterr(ECorrupt, "uncompressed wad size mismatch");
    404 			return -1;
    405 		}
    406 	}else if(w->encoding == ClumpECompress){
    407 		if(w->info.size >= w->info.uncsize){
    408 			seterr(ECorrupt, "compressed lump has inconsistent block sizes %d %d", w->info.size, w->info.uncsize);
    409 			return -1;
    410 		}
    411 	}else{
    412 		seterr(ECorrupt, "clump has illegal encoding");
    413 		return -1;
    414 	}
    415 
    416 	return 0;
    417 }
    418 
    419 int
    420 unpackclump(Clump *c, u8int *buf, u32int cmagic)
    421 {
    422 	u8int *p;
    423 	u32int magic;
    424 
    425 	p = buf;
    426 	magic = U32GET(p);
    427 	if(magic != cmagic){
    428 		seterr(ECorrupt, "clump has bad magic number=%#8.8ux != %#8.8ux", magic, cmagic);
    429 		return -1;
    430 	}
    431 	p += U32Size;
    432 
    433 	c->info.type = vtfromdisktype(U8GET(p));
    434 	p += U8Size;
    435 	c->info.size = U16GET(p);
    436 	p += U16Size;
    437 	c->info.uncsize = U16GET(p);
    438 	p += U16Size;
    439 	scorecp(c->info.score, p);
    440 	p += VtScoreSize;
    441 
    442 	c->encoding = U8GET(p);
    443 	p += U8Size;
    444 	c->creator = U32GET(p);
    445 	p += U32Size;
    446 	c->time = U32GET(p);
    447 	p += U32Size;
    448 
    449 	if(buf + ClumpSize != p)
    450 		sysfatal("unpackclump unpacked wrong amount");
    451 
    452 	return checkclump(c);
    453 }
    454 
    455 int
    456 packclump(Clump *c, u8int *buf, u32int magic)
    457 {
    458 	u8int *p;
    459 
    460 	p = buf;
    461 	U32PUT(p, magic);
    462 	p += U32Size;
    463 
    464 	U8PUT(p, vttodisktype(c->info.type));
    465 	p += U8Size;
    466 	U16PUT(p, c->info.size);
    467 	p += U16Size;
    468 	U16PUT(p, c->info.uncsize);
    469 	p += U16Size;
    470 	scorecp(p, c->info.score);
    471 	p += VtScoreSize;
    472 
    473 	U8PUT(p, c->encoding);
    474 	p += U8Size;
    475 	U32PUT(p, c->creator);
    476 	p += U32Size;
    477 	U32PUT(p, c->time);
    478 	p += U32Size;
    479 
    480 	if(buf + ClumpSize != p)
    481 		sysfatal("packclump packed wrong amount");
    482 
    483 	return checkclump(c);
    484 }
    485 
    486 void
    487 unpackclumpinfo(ClumpInfo *ci, u8int *buf)
    488 {
    489 	u8int *p;
    490 
    491 	p = buf;
    492 	ci->type = vtfromdisktype(U8GET(p));
    493 	p += U8Size;
    494 	ci->size = U16GET(p);
    495 	p += U16Size;
    496 	ci->uncsize = U16GET(p);
    497 	p += U16Size;
    498 	scorecp(ci->score, p);
    499 	p += VtScoreSize;
    500 
    501 	if(buf + ClumpInfoSize != p)
    502 		sysfatal("unpackclumpinfo unpacked wrong amount");
    503 }
    504 
    505 void
    506 packclumpinfo(ClumpInfo *ci, u8int *buf)
    507 {
    508 	u8int *p;
    509 
    510 	p = buf;
    511 	U8PUT(p, vttodisktype(ci->type));
    512 	p += U8Size;
    513 	U16PUT(p, ci->size);
    514 	p += U16Size;
    515 	U16PUT(p, ci->uncsize);
    516 	p += U16Size;
    517 	scorecp(p, ci->score);
    518 	p += VtScoreSize;
    519 
    520 	if(buf + ClumpInfoSize != p)
    521 		sysfatal("packclumpinfo packed wrong amount");
    522 }
    523 
    524 int
    525 unpackisect(ISect *is, u8int *buf)
    526 {
    527 	u8int *p;
    528 	u32int m;
    529 	char fbuf[20];
    530 
    531 	p = buf;
    532 
    533 
    534 	m = U32GET(p);
    535 	if(m != ISectMagic){
    536 		seterr(ECorrupt, "index section has wrong magic number: %s expected ISectMagic (%#lux)",
    537 			fmtmagic(fbuf, m), ISectMagic);
    538 		return -1;
    539 	}
    540 	p += U32Size;
    541 	is->version = U32GET(p);
    542 	p += U32Size;
    543 	namecp(is->name, (char*)p);
    544 	p += ANameSize;
    545 	namecp(is->index, (char*)p);
    546 	p += ANameSize;
    547 	is->blocksize = U32GET(p);
    548 	p += U32Size;
    549 	is->blockbase = U32GET(p);
    550 	p += U32Size;
    551 	is->blocks = U32GET(p);
    552 	p += U32Size;
    553 	is->start = U32GET(p);
    554 	p += U32Size;
    555 	is->stop = U32GET(p);
    556 	p += U32Size;
    557 	if(buf + ISectSize1 != p)
    558 		sysfatal("unpackisect unpacked wrong amount");
    559 	is->bucketmagic = 0;
    560 	if(is->version == ISectVersion2){
    561 		is->bucketmagic = U32GET(p);
    562 		p += U32Size;
    563 		if(buf + ISectSize2 != p)
    564 			sysfatal("unpackisect unpacked wrong amount");
    565 	}
    566 
    567 	return 0;
    568 }
    569 
    570 int
    571 packisect(ISect *is, u8int *buf)
    572 {
    573 	u8int *p;
    574 
    575 	p = buf;
    576 
    577 	U32PUT(p, ISectMagic);
    578 	p += U32Size;
    579 	U32PUT(p, is->version);
    580 	p += U32Size;
    581 	namecp((char*)p, is->name);
    582 	p += ANameSize;
    583 	namecp((char*)p, is->index);
    584 	p += ANameSize;
    585 	U32PUT(p, is->blocksize);
    586 	p += U32Size;
    587 	U32PUT(p, is->blockbase);
    588 	p += U32Size;
    589 	U32PUT(p, is->blocks);
    590 	p += U32Size;
    591 	U32PUT(p, is->start);
    592 	p += U32Size;
    593 	U32PUT(p, is->stop);
    594 	p += U32Size;
    595 	if(buf + ISectSize1 != p)
    596 		sysfatal("packisect packed wrong amount");
    597 	if(is->version == ISectVersion2){
    598 		U32PUT(p, is->bucketmagic);
    599 		p += U32Size;
    600 		if(buf + ISectSize2 != p)
    601 			sysfatal("packisect packed wrong amount");
    602 	}
    603 
    604 	return 0;
    605 }
    606 
    607 void
    608 unpackientry(IEntry *ie, u8int *buf)
    609 {
    610 	u8int *p;
    611 
    612 	p = buf;
    613 
    614 	scorecp(ie->score, p);
    615 	p += VtScoreSize;
    616 	/* ie->wtime = U32GET(p); */
    617 	p += U32Size;
    618 	/* ie->train = U16GET(p); */
    619 	p += U16Size;
    620 	if(p - buf != IEntryAddrOff)
    621 		sysfatal("unpackentry bad IEntryAddrOff amount");
    622 	ie->ia.addr = U64GET(p);
    623 if(ie->ia.addr>>56) print("%.8H => %llux\n", p, ie->ia.addr);
    624 	p += U64Size;
    625 	ie->ia.size = U16GET(p);
    626 	p += U16Size;
    627 	if(p - buf != IEntryTypeOff)
    628 		sysfatal("unpackientry bad IEntryTypeOff amount");
    629 	ie->ia.type = vtfromdisktype(U8GET(p));
    630 	p += U8Size;
    631 	ie->ia.blocks = U8GET(p);
    632 	p += U8Size;
    633 
    634 	if(p - buf != IEntrySize)
    635 		sysfatal("unpackientry unpacked wrong amount");
    636 }
    637 
    638 void
    639 packientry(IEntry *ie, u8int *buf)
    640 {
    641 	u32int t32;
    642 	u8int *p;
    643 
    644 	p = buf;
    645 
    646 	scorecp(p, ie->score);
    647 	p += VtScoreSize;
    648 	U32PUT(p, 0); /* wtime */
    649 	p += U32Size;
    650 	U16PUT(p, 0); /* train */
    651 	p += U16Size;
    652 	U64PUT(p, ie->ia.addr, t32);
    653 	p += U64Size;
    654 	U16PUT(p, ie->ia.size);
    655 	p += U16Size;
    656 	U8PUT(p, vttodisktype(ie->ia.type));
    657 	p += U8Size;
    658 	U8PUT(p, ie->ia.blocks);
    659 	p += U8Size;
    660 
    661 	if(p - buf != IEntrySize)
    662 		sysfatal("packientry packed wrong amount");
    663 }
    664 
    665 void
    666 unpackibucket(IBucket *b, u8int *buf, u32int magic)
    667 {
    668 	b->n = U16GET(buf);
    669 	b->data = buf + IBucketSize;
    670 	if(magic && magic != U32GET(buf+U16Size))
    671 		b->n = 0;
    672 }
    673 
    674 void
    675 packibucket(IBucket *b, u8int *buf, u32int magic)
    676 {
    677 	U16PUT(buf, b->n);
    678 	U32PUT(buf+U16Size, magic);
    679 }
    680 
    681 void
    682 packbloomhead(Bloom *b, u8int *buf)
    683 {
    684 	u8int *p;
    685 
    686 	p = buf;
    687 	U32PUT(p, BloomMagic);
    688 	U32PUT(p+4, BloomVersion);
    689 	U32PUT(p+8, b->nhash);
    690 	U32PUT(p+12, b->size);
    691 }
    692 
    693 int
    694 unpackbloomhead(Bloom *b, u8int *buf)
    695 {
    696 	u8int *p;
    697 	u32int m;
    698 	char fbuf[20];
    699 
    700 	p = buf;
    701 
    702 	m = U32GET(p);
    703 	if(m != BloomMagic){
    704 		seterr(ECorrupt, "bloom filter has wrong magic number: %s expected BloomMagic (%#lux)", fmtmagic(fbuf, m), (ulong)BloomMagic);
    705 		return -1;
    706 	}
    707 	p += U32Size;
    708 
    709 	m = U32GET(p);
    710 	if(m != BloomVersion){
    711 		seterr(ECorrupt, "bloom filter has wrong version %ud expected %ud", (uint)m, (uint)BloomVersion);
    712 		return -1;
    713 	}
    714 	p += U32Size;
    715 
    716 	b->nhash = U32GET(p);
    717 	p += U32Size;
    718 
    719 	b->size = U32GET(p);
    720 	p += U32Size;
    721 	if(b->size < BloomHeadSize || b->size > MaxBloomSize || (b->size&(b->size-1))){
    722 		seterr(ECorrupt, "bloom filter has invalid size %#lux", b->size);
    723 		return -1;
    724 	}
    725 
    726 	if(buf + BloomHeadSize != p)
    727 		sysfatal("unpackarena unpacked wrong amount");
    728 
    729 	return 0;
    730 }