Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 #include "whack.h"
6 /*
7 * Write a lump to disk. Updates ia with an index address
8 * for the newly-written lump. Upon return, the lump will
9 * have been placed in the disk cache but will likely not be on disk yet.
10 */
11 int
12 storeclump(Index *ix, ZBlock *zb, u8int *sc, int type, u32int creator, IAddr *ia)
13 {
14 ZBlock *cb;
15 Clump cl;
16 u64int a;
17 u8int bh[VtScoreSize];
18 int size, dsize;
20 trace(TraceLump, "storeclump enter", sc, type);
21 size = zb->len;
22 if(size > VtMaxLumpSize){
23 seterr(EStrange, "lump too large");
24 return -1;
25 }
26 if(vttypevalid(type) < 0){
27 seterr(EStrange, "invalid lump type");
28 return -1;
29 }
31 if(0){
32 scoremem(bh, zb->data, size);
33 if(scorecmp(sc, bh) != 0){
34 seterr(ECorrupt, "storing clump: corrupted; expected=%V got=%V, size=%d", sc, bh, size);
35 return -1;
36 }
37 }
39 cb = alloczblock(size + ClumpSize + U32Size, 0, 0);
40 if(cb == nil)
41 return -1;
43 cl.info.type = type;
44 cl.info.uncsize = size;
45 cl.creator = creator;
46 cl.time = now();
47 scorecp(cl.info.score, sc);
49 trace(TraceLump, "storeclump whackblock");
50 dsize = whackblock(&cb->data[ClumpSize], zb->data, size);
51 if(dsize > 0 && dsize < size){
52 cl.encoding = ClumpECompress;
53 }else{
54 if(dsize > size){
55 fprint(2, "whack error: dsize=%d size=%d\n", dsize, size);
56 abort();
57 }
58 cl.encoding = ClumpENone;
59 dsize = size;
60 memmove(&cb->data[ClumpSize], zb->data, size);
61 }
62 memset(cb->data+ClumpSize+dsize, 0, 4);
63 cl.info.size = dsize;
65 a = writeiclump(ix, &cl, cb->data);
66 trace(TraceLump, "storeclump exit %lld", a);
67 freezblock(cb);
68 if(a == TWID64)
69 return -1;
71 ia->addr = a;
72 ia->type = type;
73 ia->size = size;
74 ia->blocks = (dsize + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
76 /*
77 qlock(&stats.lock);
78 stats.clumpwrites++;
79 stats.clumpbwrites += size;
80 stats.clumpbcomp += dsize;
81 qunlock(&stats.lock);
82 */
84 return 0;
85 }
87 u32int
88 clumpmagic(Arena *arena, u64int aa)
89 {
90 u8int buf[U32Size];
92 if(readarena(arena, aa, buf, U32Size) == TWID32)
93 return TWID32;
94 return unpackmagic(buf);
95 }
97 /*
98 * fetch a block based at addr.
99 * score is filled in with the block's score.
100 * blocks is roughly the length of the clump on disk;
101 * if zero, the length is unknown.
102 */
103 ZBlock*
104 loadclump(Arena *arena, u64int aa, int blocks, Clump *cl, u8int *score, int verify)
106 Unwhack uw;
107 ZBlock *zb, *cb;
108 u8int bh[VtScoreSize], *buf;
109 u32int n;
110 int nunc;
112 /*
113 qlock(&stats.lock);
114 stats.clumpreads++;
115 qunlock(&stats.lock);
116 */
118 if(blocks <= 0)
119 blocks = 1;
121 trace(TraceLump, "loadclump enter");
123 cb = alloczblock(blocks << ABlockLog, 0, 0);
124 if(cb == nil)
125 return nil;
126 n = readarena(arena, aa, cb->data, blocks << ABlockLog);
127 if(n < ClumpSize){
128 if(n != 0)
129 seterr(ECorrupt, "loadclump read less than a header");
130 freezblock(cb);
131 return nil;
133 trace(TraceLump, "loadclump unpack");
134 if(unpackclump(cl, cb->data, arena->clumpmagic) < 0){
135 seterr(ECorrupt, "loadclump %s %llud: %r", arena->name, aa);
136 freezblock(cb);
137 return nil;
139 if(cl->info.type == VtCorruptType){
140 seterr(EOk, "clump is marked corrupt");
141 freezblock(cb);
142 return nil;
144 n -= ClumpSize;
145 if(n < cl->info.size){
146 freezblock(cb);
147 n = cl->info.size;
148 cb = alloczblock(n, 0, 0);
149 if(cb == nil)
150 return nil;
151 if(readarena(arena, aa + ClumpSize, cb->data, n) != n){
152 seterr(ECorrupt, "loadclump read too little data");
153 freezblock(cb);
154 return nil;
156 buf = cb->data;
157 }else
158 buf = cb->data + ClumpSize;
160 scorecp(score, cl->info.score);
162 zb = alloczblock(cl->info.uncsize, 0, 0);
163 if(zb == nil){
164 freezblock(cb);
165 return nil;
167 switch(cl->encoding){
168 case ClumpECompress:
169 trace(TraceLump, "loadclump decompress");
170 unwhackinit(&uw);
171 nunc = unwhack(&uw, zb->data, cl->info.uncsize, buf, cl->info.size);
172 if(nunc != cl->info.uncsize){
173 if(nunc < 0)
174 seterr(ECorrupt, "decompression of %llud failed: %s", aa, uw.err);
175 else
176 seterr(ECorrupt, "decompression of %llud gave partial block: %d/%d\n", aa, nunc, cl->info.uncsize);
177 freezblock(cb);
178 freezblock(zb);
179 return nil;
181 break;
182 case ClumpENone:
183 if(cl->info.size != cl->info.uncsize){
184 seterr(ECorrupt, "loading clump: bad uncompressed size for uncompressed block %llud", aa);
185 freezblock(cb);
186 freezblock(zb);
187 return nil;
189 scoremem(bh, buf, cl->info.uncsize);
190 if(scorecmp(cl->info.score, bh) != 0)
191 seterr(ECorrupt, "pre-copy sha1 wrong at %s %llud: expected=%V got=%V", arena->name, aa, cl->info.score, bh);
192 memmove(zb->data, buf, cl->info.uncsize);
193 break;
194 default:
195 seterr(ECorrupt, "unknown encoding in loadlump %llud", aa);
196 freezblock(cb);
197 freezblock(zb);
198 return nil;
200 freezblock(cb);
202 if(verify){
203 trace(TraceLump, "loadclump verify");
204 scoremem(bh, zb->data, cl->info.uncsize);
205 if(scorecmp(cl->info.score, bh) != 0){
206 seterr(ECorrupt, "loading clump: corrupted at %s %llud; expected=%V got=%V", arena->name, aa, cl->info.score, bh);
207 freezblock(zb);
208 return nil;
210 if(vttypevalid(cl->info.type) < 0){
211 seterr(ECorrupt, "loading lump at %s %llud: invalid lump type %d", arena->name, aa, cl->info.type);
212 freezblock(zb);
213 return nil;
217 trace(TraceLump, "loadclump exit");
218 /*
219 qlock(&stats.lock);
220 stats.clumpbreads += cl->info.size;
221 stats.clumpbuncomp += cl->info.uncsize;
222 qunlock(&stats.lock);
223 */
224 return zb;