123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- #include "stdinc.h"
- #include "dat.h"
- #include "fns.h"
- #include "whack.h"
- /*
- * Write a lump to disk. Updates ia with an index address
- * for the newly-written lump. Upon return, the lump will
- * have been placed in the disk cache but will likely not be on disk yet.
- */
- int
- storeclump(Index *ix, ZBlock *zb, u8int *sc, int type, u32int creator, IAddr *ia)
- {
- ZBlock *cb;
- Clump cl;
- u64int a;
- u8int bh[VtScoreSize];
- int size, dsize;
- trace(TraceLump, "storeclump enter", sc, type);
- size = zb->len;
- if(size > VtMaxLumpSize){
- seterr(EStrange, "lump too large");
- return -1;
- }
- if(vttypevalid(type) < 0){
- seterr(EStrange, "invalid lump type");
- return -1;
- }
- if(0){
- scoremem(bh, zb->data, size);
- if(scorecmp(sc, bh) != 0){
- seterr(ECorrupt, "storing clump: corrupted; expected=%V got=%V, size=%d", sc, bh, size);
- return -1;
- }
- }
- cb = alloczblock(size + ClumpSize + U32Size, 0, 0);
- if(cb == nil)
- return -1;
- cl.info.type = type;
- cl.info.uncsize = size;
- cl.creator = creator;
- cl.time = now();
- scorecp(cl.info.score, sc);
- trace(TraceLump, "storeclump whackblock");
- dsize = whackblock(&cb->data[ClumpSize], zb->data, size);
- if(dsize > 0 && dsize < size){
- cl.encoding = ClumpECompress;
- }else{
- if(dsize > size){
- fprint(2, "whack error: dsize=%d size=%d\n", dsize, size);
- abort();
- }
- cl.encoding = ClumpENone;
- dsize = size;
- memmove(&cb->data[ClumpSize], zb->data, size);
- }
- memset(cb->data+ClumpSize+dsize, 0, 4);
- cl.info.size = dsize;
- a = writeiclump(ix, &cl, cb->data);
- trace(TraceLump, "storeclump exit %lld", a);
- freezblock(cb);
- if(a == TWID64)
- return -1;
- ia->addr = a;
- ia->type = type;
- ia->size = size;
- ia->blocks = (dsize + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
- /*
- qlock(&stats.lock);
- stats.clumpwrites++;
- stats.clumpbwrites += size;
- stats.clumpbcomp += dsize;
- qunlock(&stats.lock);
- */
- return 0;
- }
- u32int
- clumpmagic(Arena *arena, u64int aa)
- {
- u8int buf[U32Size];
- if(readarena(arena, aa, buf, U32Size) == TWID32)
- return TWID32;
- return unpackmagic(buf);
- }
- /*
- * fetch a block based at addr.
- * score is filled in with the block's score.
- * blocks is roughly the length of the clump on disk;
- * if zero, the length is unknown.
- */
- ZBlock*
- loadclump(Arena *arena, u64int aa, int blocks, Clump *cl, u8int *score, int verify)
- {
- Unwhack uw;
- ZBlock *zb, *cb;
- u8int bh[VtScoreSize], *buf;
- u32int n;
- int nunc;
- /*
- qlock(&stats.lock);
- stats.clumpreads++;
- qunlock(&stats.lock);
- */
- if(blocks <= 0)
- blocks = 1;
- trace(TraceLump, "loadclump enter");
- cb = alloczblock(blocks << ABlockLog, 0, 0);
- if(cb == nil)
- return nil;
- n = readarena(arena, aa, cb->data, blocks << ABlockLog);
- if(n < ClumpSize){
- if(n != 0)
- seterr(ECorrupt, "loadclump read less than a header");
- freezblock(cb);
- return nil;
- }
- trace(TraceLump, "loadclump unpack");
- if(unpackclump(cl, cb->data, arena->clumpmagic) < 0){
- seterr(ECorrupt, "loadclump %s %llud: %r", arena->name, aa);
- freezblock(cb);
- return nil;
- }
- if(cl->info.type == VtCorruptType){
- seterr(EOk, "clump is marked corrupt");
- freezblock(cb);
- return nil;
- }
- n -= ClumpSize;
- if(n < cl->info.size){
- freezblock(cb);
- n = cl->info.size;
- cb = alloczblock(n, 0, 0);
- if(cb == nil)
- return nil;
- if(readarena(arena, aa + ClumpSize, cb->data, n) != n){
- seterr(ECorrupt, "loadclump read too little data");
- freezblock(cb);
- return nil;
- }
- buf = cb->data;
- }else
- buf = cb->data + ClumpSize;
- scorecp(score, cl->info.score);
- zb = alloczblock(cl->info.uncsize, 0, 0);
- if(zb == nil){
- freezblock(cb);
- return nil;
- }
- switch(cl->encoding){
- case ClumpECompress:
- trace(TraceLump, "loadclump decompress");
- unwhackinit(&uw);
- nunc = unwhack(&uw, zb->data, cl->info.uncsize, buf, cl->info.size);
- if(nunc != cl->info.uncsize){
- if(nunc < 0)
- seterr(ECorrupt, "decompression of %llud failed: %s", aa, uw.err);
- else
- seterr(ECorrupt, "decompression of %llud gave partial block: %d/%d\n", aa, nunc, cl->info.uncsize);
- freezblock(cb);
- freezblock(zb);
- return nil;
- }
- break;
- case ClumpENone:
- if(cl->info.size != cl->info.uncsize){
- seterr(ECorrupt, "loading clump: bad uncompressed size for uncompressed block %llud", aa);
- freezblock(cb);
- freezblock(zb);
- return nil;
- }
- scoremem(bh, buf, cl->info.uncsize);
- if(scorecmp(cl->info.score, bh) != 0)
- seterr(ECorrupt, "pre-copy sha1 wrong at %s %llud: expected=%V got=%V", arena->name, aa, cl->info.score, bh);
- memmove(zb->data, buf, cl->info.uncsize);
- break;
- default:
- seterr(ECorrupt, "unknown encoding in loadlump %llud", aa);
- freezblock(cb);
- freezblock(zb);
- return nil;
- }
- freezblock(cb);
- if(verify){
- trace(TraceLump, "loadclump verify");
- scoremem(bh, zb->data, cl->info.uncsize);
- if(scorecmp(cl->info.score, bh) != 0){
- seterr(ECorrupt, "loading clump: corrupted at %s %llud; expected=%V got=%V", arena->name, aa, cl->info.score, bh);
- freezblock(zb);
- return nil;
- }
- if(vttypevalid(cl->info.type) < 0){
- seterr(ECorrupt, "loading lump at %s %llud: invalid lump type %d", arena->name, aa, cl->info.type);
- freezblock(zb);
- return nil;
- }
- }
- trace(TraceLump, "loadclump exit");
- /*
- qlock(&stats.lock);
- stats.clumpbreads += cl->info.size;
- stats.clumpbuncomp += cl->info.uncsize;
- qunlock(&stats.lock);
- */
- return zb;
- }
|