Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 #include "whack.h"
6 /*
7 * writes a lump to disk
8 * returns the address in amap of the clump
9 */
10 int
11 storeclump(Index *ix, ZBlock *zb, u8int *sc, int type, u32int creator, IAddr *ia)
12 {
13 ZBlock *cb;
14 Clump cl;
15 u64int a;
16 u8int bh[VtScoreSize];
17 int size, dsize;
19 if(0)print("storeclump %08x %p\n", mainindex->arenas[0], &cl);
20 size = zb->len;
21 if(size > VtMaxLumpSize){
22 seterr(EStrange, "lump too large");
23 return -1;
24 }
25 if(vttypevalid(type) < 0){
26 seterr(EStrange, "invalid lump type");
27 return -1;
28 }
30 if(1){
31 scoremem(bh, zb->data, size);
32 if(scorecmp(sc, bh) != 0){
33 seterr(ECorrupt, "storing clump: corrupted; expected=%V got=%V, size=%d", sc, bh, size);
34 return -1;
35 }
36 }
38 cb = alloczblock(size + ClumpSize, 0);
39 if(cb == nil)
40 return -1;
42 cl.info.type = type;
43 cl.info.uncsize = size;
44 cl.creator = creator;
45 cl.time = now();
46 scorecp(cl.info.score, sc);
48 if(0)print("whackblock %08x %p\n", mainindex->arenas[0], &cl);
49 dsize = whackblock(&cb->data[ClumpSize], zb->data, size);
50 if(0)print("whackedblock %08x %p\n", mainindex->arenas[0], &cl);
51 if(dsize > 0 && dsize < size){
52 cl.encoding = ClumpECompress;
53 }else{
54 cl.encoding = ClumpENone;
55 dsize = size;
56 memmove(&cb->data[ClumpSize], zb->data, size);
57 }
58 cl.info.size = dsize;
60 a = writeiclump(ix, &cl, cb->data);
62 freezblock(cb);
63 if(a == 0)
64 return -1;
66 qlock(&stats.lock);
67 stats.clumpwrites++;
68 stats.clumpbwrites += size;
69 stats.clumpbcomp += dsize;
70 qunlock(&stats.lock);
72 ia->addr = a;
73 ia->type = type;
74 ia->size = size;
75 ia->blocks = (dsize + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
77 return 0;
78 }
80 u32int
81 clumpmagic(Arena *arena, u64int aa)
82 {
83 u8int buf[U32Size];
85 if(readarena(arena, aa, buf, U32Size) < 0)
86 return TWID32;
87 return unpackmagic(buf);
88 }
90 /*
91 * fetch a block based at addr.
92 * score is filled in with the block's score.
93 * blocks is roughly the length of the clump on disk;
94 * if zero, the length is unknown.
95 */
96 ZBlock*
97 loadclump(Arena *arena, u64int aa, int blocks, Clump *cl, u8int *score, int verify)
98 {
99 Unwhack uw;
100 ZBlock *zb, *cb;
101 u8int bh[VtScoreSize], *buf;
102 u32int n;
103 int nunc;
105 qlock(&stats.lock);
106 stats.clumpreads++;
107 qunlock(&stats.lock);
109 if(blocks <= 0)
110 blocks = 1;
112 cb = alloczblock(blocks << ABlockLog, 0);
113 if(cb == nil)
114 return nil;
115 n = readarena(arena, aa, cb->data, blocks << ABlockLog);
116 if(n < ClumpSize){
117 if(n != 0)
118 seterr(ECorrupt, "loadclump read less than a header");
119 freezblock(cb);
120 return nil;
122 if(unpackclump(cl, cb->data) < 0){
123 freezblock(cb);
124 return nil;
126 n -= ClumpSize;
127 if(n < cl->info.size){
128 freezblock(cb);
129 n = cl->info.size;
130 cb = alloczblock(n, 0);
131 if(cb == nil)
132 return nil;
133 if(readarena(arena, aa + ClumpSize, cb->data, n) != n){
134 seterr(ECorrupt, "loadclump read too little data");
135 freezblock(cb);
136 return nil;
138 buf = cb->data;
139 }else
140 buf = cb->data + ClumpSize;
142 scorecp(score, cl->info.score);
144 zb = alloczblock(cl->info.uncsize, 0);
145 if(zb == nil){
146 freezblock(cb);
147 return nil;
149 switch(cl->encoding){
150 case ClumpECompress:
151 unwhackinit(&uw);
152 nunc = unwhack(&uw, zb->data, cl->info.uncsize, buf, cl->info.size);
153 if(nunc != cl->info.uncsize){
154 if(nunc < 0)
155 seterr(ECorrupt, "decompression failed: %s", uw.err);
156 else
157 seterr(ECorrupt, "decompression gave partial block: %d/%d\n", nunc, cl->info.uncsize);
158 freezblock(cb);
159 freezblock(zb);
160 return nil;
162 break;
163 case ClumpENone:
164 if(cl->info.size != cl->info.uncsize){
165 seterr(ECorrupt, "loading clump: bad uncompressed size for uncompressed block");
166 freezblock(cb);
167 freezblock(zb);
168 return nil;
170 memmove(zb->data, buf, cl->info.uncsize);
171 break;
172 default:
173 seterr(ECorrupt, "unknown encoding in loadlump");
174 freezblock(cb);
175 freezblock(zb);
176 return nil;
178 freezblock(cb);
180 if(verify){
181 scoremem(bh, zb->data, cl->info.uncsize);
182 if(scorecmp(cl->info.score, bh) != 0){
183 seterr(ECorrupt, "loading clump: corrupted; expected=%V got=%V", cl->info.score, bh);
184 freezblock(zb);
185 return nil;
187 if(vttypevalid(cl->info.type) < 0){
188 seterr(ECorrupt, "loading lump: invalid lump type %d", cl->info.type);
189 freezblock(zb);
190 return nil;
194 qlock(&stats.lock);
195 stats.clumpbreads += cl->info.size;
196 stats.clumpbuncomp += cl->info.uncsize;
197 qunlock(&stats.lock);
199 return zb;