clump.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. #include "whack.h"
  5. /*
  6. * writes a lump to disk
  7. * returns the address in amap of the clump
  8. */
  9. int
  10. storeClump(Index *ix, ZBlock *zb, u8int *sc, int type, u32int creator, IAddr *ia)
  11. {
  12. ZBlock *cb;
  13. Clump cl;
  14. u64int a;
  15. u8int bh[VtScoreSize];
  16. int size, dsize;
  17. size = zb->len;
  18. if(size > VtMaxLumpSize){
  19. setErr(EStrange, "lump too large");
  20. return 0;
  21. }
  22. if(!vtTypeValid(type)){
  23. setErr(EStrange, "invalid lump type");
  24. return 0;
  25. }
  26. if(1){
  27. scoreMem(bh, zb->data, size);
  28. if(!scoreEq(sc, bh)){
  29. setErr(ECorrupt, "storing clump: corrupted; expected=%V got=%V, size=%d", sc, bh, size);
  30. return 0;
  31. }
  32. }
  33. cb = allocZBlock(size + ClumpSize, 0);
  34. if(cb == nil)
  35. return 0;
  36. cl.info.type = type;
  37. cl.info.uncsize = size;
  38. cl.creator = creator;
  39. cl.time = now();
  40. scoreCp(cl.info.score, sc);
  41. dsize = whackblock(&cb->data[ClumpSize], zb->data, size);
  42. if(dsize > 0 && dsize < size){
  43. cl.encoding = ClumpECompress;
  44. }else{
  45. cl.encoding = ClumpENone;
  46. dsize = size;
  47. memmove(&cb->data[ClumpSize], zb->data, size);
  48. }
  49. cl.info.size = dsize;
  50. a = writeIClump(ix, &cl, cb->data);
  51. freeZBlock(cb);
  52. if(a == 0)
  53. return 0;
  54. vtLock(stats.lock);
  55. stats.clumpWrites++;
  56. stats.clumpBWrites += size;
  57. stats.clumpBComp += dsize;
  58. vtUnlock(stats.lock);
  59. ia->addr = a;
  60. ia->type = type;
  61. ia->size = size;
  62. ia->blocks = (dsize + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
  63. return 1;
  64. }
  65. u32int
  66. clumpMagic(Arena *arena, u64int aa)
  67. {
  68. u8int buf[U32Size];
  69. if(!readArena(arena, aa, buf, U32Size))
  70. return TWID32;
  71. return unpackMagic(buf);
  72. }
  73. /*
  74. * fetch a block based at addr.
  75. * score is filled in with the block's score.
  76. * blocks is roughly the length of the clump on disk;
  77. * if zero, the length is unknown.
  78. */
  79. ZBlock*
  80. loadClump(Arena *arena, u64int aa, int blocks, Clump *cl, u8int *score, int verify)
  81. {
  82. Unwhack uw;
  83. ZBlock *zb, *cb;
  84. u8int bh[VtScoreSize], *buf;
  85. u32int n;
  86. int nunc;
  87. vtLock(stats.lock);
  88. stats.clumpReads++;
  89. vtUnlock(stats.lock);
  90. if(blocks <= 0)
  91. blocks = 1;
  92. cb = allocZBlock(blocks << ABlockLog, 0);
  93. if(cb == nil)
  94. return nil;
  95. n = readArena(arena, aa, cb->data, blocks << ABlockLog);
  96. if(n < ClumpSize){
  97. if(n != 0)
  98. setErr(ECorrupt, "loadClump read less than a header");
  99. freeZBlock(cb);
  100. return nil;
  101. }
  102. if(!unpackClump(cl, cb->data)){
  103. freeZBlock(cb);
  104. return nil;
  105. }
  106. n -= ClumpSize;
  107. if(n < cl->info.size){
  108. freeZBlock(cb);
  109. n = cl->info.size;
  110. cb = allocZBlock(n, 0);
  111. if(cb == nil)
  112. return nil;
  113. if(readArena(arena, aa + ClumpSize, cb->data, n) != n){
  114. setErr(ECorrupt, "loadClump read too little data");
  115. freeZBlock(cb);
  116. return nil;
  117. }
  118. buf = cb->data;
  119. }else
  120. buf = cb->data + ClumpSize;
  121. scoreCp(score, cl->info.score);
  122. zb = allocZBlock(cl->info.uncsize, 0);
  123. if(zb == nil){
  124. freeZBlock(cb);
  125. return nil;
  126. }
  127. switch(cl->encoding){
  128. case ClumpECompress:
  129. unwhackinit(&uw);
  130. nunc = unwhack(&uw, zb->data, cl->info.uncsize, buf, cl->info.size);
  131. if(nunc != cl->info.uncsize){
  132. if(nunc < 0)
  133. setErr(ECorrupt, "decompression failed: %s", uw.err);
  134. else
  135. setErr(ECorrupt, "decompression gave partial block: %d/%d\n", nunc, cl->info.uncsize);
  136. freeZBlock(cb);
  137. freeZBlock(zb);
  138. return nil;
  139. }
  140. break;
  141. case ClumpENone:
  142. if(cl->info.size != cl->info.uncsize){
  143. setErr(ECorrupt, "loading clump: bad uncompressed size for uncompressed block");
  144. freeZBlock(cb);
  145. freeZBlock(zb);
  146. return nil;
  147. }
  148. memmove(zb->data, buf, cl->info.uncsize);
  149. break;
  150. default:
  151. setErr(ECorrupt, "unknown encoding in loadLump");
  152. freeZBlock(cb);
  153. freeZBlock(zb);
  154. return nil;
  155. }
  156. freeZBlock(cb);
  157. if(verify){
  158. scoreMem(bh, zb->data, cl->info.uncsize);
  159. if(!scoreEq(cl->info.score, bh)){
  160. setErr(ECorrupt, "loading clump: corrupted; expected=%V got=%V", cl->info.score, bh);
  161. freeZBlock(zb);
  162. return nil;
  163. }
  164. if(!vtTypeValid(cl->info.type)){
  165. setErr(ECorrupt, "loading lump: invalid lump type %d", cl->info.type);
  166. freeZBlock(zb);
  167. return nil;
  168. }
  169. }
  170. vtLock(stats.lock);
  171. stats.clumpBReads += cl->info.size;
  172. stats.clumpBUncomp += cl->info.uncsize;
  173. vtUnlock(stats.lock);
  174. return zb;
  175. }