#include "stdinc.h" #include "dat.h" #include "fns.h" /* * disk structure conversion routines */ #define U8GET(p) ((p)[0]) #define U16GET(p) (((p)[0]<<8)|(p)[1]) #define U32GET(p) ((u32int)(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])) #define U64GET(p) (((u64int)U32GET(p)<<32)|(u64int)U32GET((p)+4)) #define U8PUT(p,v) (p)[0]=(v)&0xFF #define U16PUT(p,v) (p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF #define U32PUT(p,v) (p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32) int debugarena = -1; /* hack to improve error reporting */ static struct { u32int m; char *s; } magics[] = { ArenaPartMagic, "ArenaPartMagic", ArenaHeadMagic, "ArenaHeadMagic", ArenaMagic, "ArenaMagic", ISectMagic, "ISectMagic", BloomMagic, "BloomMagic", }; static char* fmtmagic(char *s, u32int m) { int i; for(i=0; iversion = U32GET(p); p += U32Size; ap->blocksize = U32GET(p); p += U32Size; ap->arenabase = U32GET(p); p += U32Size; if(buf + ArenaPartSize != p) sysfatal("unpackarenapart unpacked wrong amount"); return 0; } int packarenapart(ArenaPart *ap, u8int *buf) { u8int *p; p = buf; U32PUT(p, ArenaPartMagic); p += U32Size; U32PUT(p, ap->version); p += U32Size; U32PUT(p, ap->blocksize); p += U32Size; U32PUT(p, ap->arenabase); p += U32Size; if(buf + ArenaPartSize != p) sysfatal("packarenapart packed wrong amount"); return 0; } int unpackarena(Arena *arena, u8int *buf) { int sz; u8int *p; u32int m; char fbuf[20]; p = buf; m = U32GET(p); if(m != ArenaMagic){ seterr(ECorrupt, "arena %d has wrong magic number: %s " "expected ArenaMagic (%#lux)", debugarena, fmtmagic(fbuf, m), ArenaMagic); return -1; } p += U32Size; arena->version = U32GET(p); p += U32Size; namecp(arena->name, (char*)p); p += ANameSize; arena->diskstats.clumps = U32GET(p); p += U32Size; arena->diskstats.cclumps = U32GET(p); p += U32Size; arena->ctime = U32GET(p); p += U32Size; arena->wtime = U32GET(p); p += U32Size; if(arena->version == ArenaVersion5){ arena->clumpmagic = U32GET(p); p += U32Size; } arena->diskstats.used = U64GET(p); p += U64Size; arena->diskstats.uncsize = U64GET(p); p += U64Size; arena->diskstats.sealed = U8GET(p); p += U8Size; switch(arena->version){ case ArenaVersion4: sz = ArenaSize4; arena->clumpmagic = _ClumpMagic; break; case ArenaVersion5: sz = ArenaSize5; break; default: seterr(ECorrupt, "arena has bad version number %d", arena->version); return -1; } /* * Additional fields for the memstats version of the stats. * Diskstats reflects what is committed to the index. * Memstats reflects what is in the arena. Originally intended * this to be a version 5 extension, but might as well use for * all the existing version 4 arenas too. * * To maintain backwards compatibility with existing venti * installations using the older format, we define that if * memstats == diskstats, then the extension fields are not * included (see packarena below). That is, only partially * indexed arenas have these fields. Fully indexed arenas * (in particular, sealed arenas) do not. */ if(U8GET(p) == 1){ sz += ArenaSize5a-ArenaSize5; p += U8Size; arena->memstats.clumps = U32GET(p); p += U32Size; arena->memstats.cclumps = U32GET(p); p += U32Size; arena->memstats.used = U64GET(p); p += U64Size; arena->memstats.uncsize = U64GET(p); p += U64Size; arena->memstats.sealed = U8GET(p); p += U8Size; /* * 2008/4/2 * Packarena (below) used to have a bug in which it would * not zero out any existing extension fields when writing * the arena metadata. This would manifest itself as arenas * with arena->diskstats.sealed == 1 but arena->memstats.sealed == 0 * after a server restart. Because arena->memstats.sealed wouldn't * be set, the server might try to fit another block into the arena * (and succeed), violating the append-only structure of the log * and invalidating any already-computed seal on the arena. * * It might end up that other fields in arena->memstats end up * behind arena->diskstats too, but that would be considerably * more rare, and the bug is fixed now. The case we need to * handle is just the sealed mismatch. * * If we encounter such a bogus arena, fix the sealed field. */ if(arena->diskstats.sealed) arena->memstats.sealed = 1; }else arena->memstats = arena->diskstats; if(buf + sz != p) sysfatal("unpackarena unpacked wrong amount"); return 0; } int packarena(Arena *arena, u8int *buf) { return _packarena(arena, buf, 0); } int _packarena(Arena *arena, u8int *buf, int forceext) { int sz; u8int *p; u32int t32; switch(arena->version){ case ArenaVersion4: sz = ArenaSize4; if(arena->clumpmagic != _ClumpMagic) fprint(2, "warning: writing old arena tail loses clump magic 0x%lux != 0x%lux\n", (ulong)arena->clumpmagic, (ulong)_ClumpMagic); break; case ArenaVersion5: sz = ArenaSize5; break; default: sysfatal("packarena unknown version %d", arena->version); return -1; } p = buf; U32PUT(p, ArenaMagic); p += U32Size; U32PUT(p, arena->version); p += U32Size; namecp((char*)p, arena->name); p += ANameSize; U32PUT(p, arena->diskstats.clumps); p += U32Size; U32PUT(p, arena->diskstats.cclumps); p += U32Size; U32PUT(p, arena->ctime); p += U32Size; U32PUT(p, arena->wtime); p += U32Size; if(arena->version == ArenaVersion5){ U32PUT(p, arena->clumpmagic); p += U32Size; } U64PUT(p, arena->diskstats.used, t32); p += U64Size; U64PUT(p, arena->diskstats.uncsize, t32); p += U64Size; U8PUT(p, arena->diskstats.sealed); p += U8Size; /* * Extension fields; see above. */ if(forceext || arena->memstats.clumps != arena->diskstats.clumps || arena->memstats.cclumps != arena->diskstats.cclumps || arena->memstats.used != arena->diskstats.used || arena->memstats.uncsize != arena->diskstats.uncsize || arena->memstats.sealed != arena->diskstats.sealed){ sz += ArenaSize5a - ArenaSize5; U8PUT(p, 1); p += U8Size; U32PUT(p, arena->memstats.clumps); p += U32Size; U32PUT(p, arena->memstats.cclumps); p += U32Size; U64PUT(p, arena->memstats.used, t32); p += U64Size; U64PUT(p, arena->memstats.uncsize, t32); p += U64Size; U8PUT(p, arena->memstats.sealed); p += U8Size; }else{ /* Clear any extension fields already on disk. */ memset(p, 0, ArenaSize5a - ArenaSize5); p += ArenaSize5a - ArenaSize5; sz += ArenaSize5a - ArenaSize5; } if(buf + sz != p) sysfatal("packarena packed wrong amount"); return 0; } int unpackarenahead(ArenaHead *head, u8int *buf) { u8int *p; u32int m; int sz; char fbuf[20]; p = buf; m = U32GET(p); if(m != ArenaHeadMagic){ seterr(ECorrupt, "arena %d head has wrong magic number: %s " "expected ArenaHeadMagic (%#lux)", debugarena, fmtmagic(fbuf, m), ArenaHeadMagic); return -1; } p += U32Size; head->version = U32GET(p); p += U32Size; namecp(head->name, (char*)p); p += ANameSize; head->blocksize = U32GET(p); p += U32Size; head->size = U64GET(p); p += U64Size; if(head->version == ArenaVersion5){ head->clumpmagic = U32GET(p); p += U32Size; } switch(head->version){ case ArenaVersion4: sz = ArenaHeadSize4; head->clumpmagic = _ClumpMagic; break; case ArenaVersion5: sz = ArenaHeadSize5; break; default: seterr(ECorrupt, "arena head has unexpected version %d", head->version); return -1; } if(buf + sz != p) sysfatal("unpackarenahead unpacked wrong amount"); return 0; } int packarenahead(ArenaHead *head, u8int *buf) { u8int *p; int sz; u32int t32; switch(head->version){ case ArenaVersion4: sz = ArenaHeadSize4; if(head->clumpmagic != _ClumpMagic) fprint(2, "warning: writing old arena header loses clump magic 0x%lux != 0x%lux\n", (ulong)head->clumpmagic, (ulong)_ClumpMagic); break; case ArenaVersion5: sz = ArenaHeadSize5; break; default: sysfatal("packarenahead unknown version %d", head->version); return -1; } p = buf; U32PUT(p, ArenaHeadMagic); p += U32Size; U32PUT(p, head->version); p += U32Size; namecp((char*)p, head->name); p += ANameSize; U32PUT(p, head->blocksize); p += U32Size; U64PUT(p, head->size, t32); p += U64Size; if(head->version == ArenaVersion5){ U32PUT(p, head->clumpmagic); p += U32Size; } if(buf + sz != p) sysfatal("packarenahead packed wrong amount"); return 0; } static int checkclump(Clump *w) { if(w->encoding == ClumpENone){ if(w->info.size != w->info.uncsize){ seterr(ECorrupt, "uncompressed wad size mismatch"); return -1; } }else if(w->encoding == ClumpECompress){ if(w->info.size >= w->info.uncsize){ seterr(ECorrupt, "compressed lump has inconsistent block sizes %d %d", w->info.size, w->info.uncsize); return -1; } }else{ seterr(ECorrupt, "clump has illegal encoding"); return -1; } return 0; } int unpackclump(Clump *c, u8int *buf, u32int cmagic) { u8int *p; u32int magic; p = buf; magic = U32GET(p); if(magic != cmagic){ seterr(ECorrupt, "clump has bad magic number=%#8.8ux != %#8.8ux", magic, cmagic); return -1; } p += U32Size; c->info.type = vtfromdisktype(U8GET(p)); p += U8Size; c->info.size = U16GET(p); p += U16Size; c->info.uncsize = U16GET(p); p += U16Size; scorecp(c->info.score, p); p += VtScoreSize; c->encoding = U8GET(p); p += U8Size; c->creator = U32GET(p); p += U32Size; c->time = U32GET(p); p += U32Size; if(buf + ClumpSize != p) sysfatal("unpackclump unpacked wrong amount"); return checkclump(c); } int packclump(Clump *c, u8int *buf, u32int magic) { u8int *p; p = buf; U32PUT(p, magic); p += U32Size; U8PUT(p, vttodisktype(c->info.type)); p += U8Size; U16PUT(p, c->info.size); p += U16Size; U16PUT(p, c->info.uncsize); p += U16Size; scorecp(p, c->info.score); p += VtScoreSize; U8PUT(p, c->encoding); p += U8Size; U32PUT(p, c->creator); p += U32Size; U32PUT(p, c->time); p += U32Size; if(buf + ClumpSize != p) sysfatal("packclump packed wrong amount"); return checkclump(c); } void unpackclumpinfo(ClumpInfo *ci, u8int *buf) { u8int *p; p = buf; ci->type = vtfromdisktype(U8GET(p)); p += U8Size; ci->size = U16GET(p); p += U16Size; ci->uncsize = U16GET(p); p += U16Size; scorecp(ci->score, p); p += VtScoreSize; if(buf + ClumpInfoSize != p) sysfatal("unpackclumpinfo unpacked wrong amount"); } void packclumpinfo(ClumpInfo *ci, u8int *buf) { u8int *p; p = buf; U8PUT(p, vttodisktype(ci->type)); p += U8Size; U16PUT(p, ci->size); p += U16Size; U16PUT(p, ci->uncsize); p += U16Size; scorecp(p, ci->score); p += VtScoreSize; if(buf + ClumpInfoSize != p) sysfatal("packclumpinfo packed wrong amount"); } int unpackisect(ISect *is, u8int *buf) { u8int *p; u32int m; char fbuf[20]; p = buf; m = U32GET(p); if(m != ISectMagic){ seterr(ECorrupt, "index section has wrong magic number: %s expected ISectMagic (%#lux)", fmtmagic(fbuf, m), ISectMagic); return -1; } p += U32Size; is->version = U32GET(p); p += U32Size; namecp(is->name, (char*)p); p += ANameSize; namecp(is->index, (char*)p); p += ANameSize; is->blocksize = U32GET(p); p += U32Size; is->blockbase = U32GET(p); p += U32Size; is->blocks = U32GET(p); p += U32Size; is->start = U32GET(p); p += U32Size; is->stop = U32GET(p); p += U32Size; if(buf + ISectSize1 != p) sysfatal("unpackisect unpacked wrong amount"); is->bucketmagic = 0; if(is->version == ISectVersion2){ is->bucketmagic = U32GET(p); p += U32Size; if(buf + ISectSize2 != p) sysfatal("unpackisect unpacked wrong amount"); } return 0; } int packisect(ISect *is, u8int *buf) { u8int *p; p = buf; U32PUT(p, ISectMagic); p += U32Size; U32PUT(p, is->version); p += U32Size; namecp((char*)p, is->name); p += ANameSize; namecp((char*)p, is->index); p += ANameSize; U32PUT(p, is->blocksize); p += U32Size; U32PUT(p, is->blockbase); p += U32Size; U32PUT(p, is->blocks); p += U32Size; U32PUT(p, is->start); p += U32Size; U32PUT(p, is->stop); p += U32Size; if(buf + ISectSize1 != p) sysfatal("packisect packed wrong amount"); if(is->version == ISectVersion2){ U32PUT(p, is->bucketmagic); p += U32Size; if(buf + ISectSize2 != p) sysfatal("packisect packed wrong amount"); } return 0; } void unpackientry(IEntry *ie, u8int *buf) { u8int *p; p = buf; scorecp(ie->score, p); p += VtScoreSize; /* ie->wtime = U32GET(p); */ p += U32Size; /* ie->train = U16GET(p); */ p += U16Size; if(p - buf != IEntryAddrOff) sysfatal("unpackentry bad IEntryAddrOff amount"); ie->ia.addr = U64GET(p); if(ie->ia.addr>>56) print("%.8H => %llux\n", p, ie->ia.addr); p += U64Size; ie->ia.size = U16GET(p); p += U16Size; if(p - buf != IEntryTypeOff) sysfatal("unpackientry bad IEntryTypeOff amount"); ie->ia.type = vtfromdisktype(U8GET(p)); p += U8Size; ie->ia.blocks = U8GET(p); p += U8Size; if(p - buf != IEntrySize) sysfatal("unpackientry unpacked wrong amount"); } void packientry(IEntry *ie, u8int *buf) { u32int t32; u8int *p; p = buf; scorecp(p, ie->score); p += VtScoreSize; U32PUT(p, 0); /* wtime */ p += U32Size; U16PUT(p, 0); /* train */ p += U16Size; U64PUT(p, ie->ia.addr, t32); p += U64Size; U16PUT(p, ie->ia.size); p += U16Size; U8PUT(p, vttodisktype(ie->ia.type)); p += U8Size; U8PUT(p, ie->ia.blocks); p += U8Size; if(p - buf != IEntrySize) sysfatal("packientry packed wrong amount"); } void unpackibucket(IBucket *b, u8int *buf, u32int magic) { b->n = U16GET(buf); b->data = buf + IBucketSize; if(magic && magic != U32GET(buf+U16Size)) b->n = 0; } void packibucket(IBucket *b, u8int *buf, u32int magic) { U16PUT(buf, b->n); U32PUT(buf+U16Size, magic); } void packbloomhead(Bloom *b, u8int *buf) { u8int *p; p = buf; U32PUT(p, BloomMagic); U32PUT(p+4, BloomVersion); U32PUT(p+8, b->nhash); U32PUT(p+12, b->size); } int unpackbloomhead(Bloom *b, u8int *buf) { u8int *p; u32int m; char fbuf[20]; p = buf; m = U32GET(p); if(m != BloomMagic){ seterr(ECorrupt, "bloom filter has wrong magic number: %s expected BloomMagic (%#lux)", fmtmagic(fbuf, m), (ulong)BloomMagic); return -1; } p += U32Size; m = U32GET(p); if(m != BloomVersion){ seterr(ECorrupt, "bloom filter has wrong version %ud expected %ud", (uint)m, (uint)BloomVersion); return -1; } p += U32Size; b->nhash = U32GET(p); p += U32Size; b->size = U32GET(p); p += U32Size; if(b->size < BloomHeadSize || b->size > MaxBloomSize || (b->size&(b->size-1))){ seterr(ECorrupt, "bloom filter has invalid size %#lux", b->size); return -1; } if(buf + BloomHeadSize != p) sysfatal("unpackarena unpacked wrong amount"); return 0; }