rev |
line source |
pascal@23682
|
1 --- block/cloop.c
|
pascal@23682
|
2 +++ block/cloop.c
|
pascal@23680
|
3 @@ -25,33 +25,206 @@
|
pascal@23680
|
4 #include "block/block_int.h"
|
pascal@23680
|
5 #include "qemu/module.h"
|
pascal@23680
|
6 #include <zlib.h>
|
pascal@23680
|
7 +#include <lzma.h>
|
pascal@23680
|
8 +
|
pascal@23680
|
9 +#define CLOOP_COMPRESSOR_ZLIB 0x0
|
pascal@23680
|
10 +#define CLOOP_COMPRESSOR_NONE 0x1
|
pascal@23680
|
11 +#define CLOOP_COMPRESSOR_XZ 0x2
|
pascal@23680
|
12 +#define CLOOP_COMPRESSOR_LZ4 0x3
|
pascal@23680
|
13 +#define CLOOP_COMPRESSOR_LZO 0x4
|
pascal@23680
|
14 +#define CLOOP_COMPRESSOR_ZSTD 0x5
|
pascal@23680
|
15 +#define CLOOP_COMPRESSOR_LINK 0xF
|
pascal@23680
|
16 +
|
pascal@23680
|
17 +#define CLOOP_BLOCK_FLAGS(x) ((unsigned int)(((x) & 0xf000000000000000LLU) >> 60))
|
pascal@23680
|
18 +#define CLOOP_BLOCK_OFFSET(x) ((x) & 0x0fffffffffffffffLLU)
|
pascal@23680
|
19
|
pascal@17989
|
20 /* Maximum compressed block size */
|
pascal@17989
|
21 #define MAX_BLOCK_SIZE (64 * 1024 * 1024)
|
pascal@17266
|
22
|
pascal@17266
|
23 +typedef struct cloop_tail {
|
pascal@17266
|
24 + uint32_t table_size;
|
pascal@17266
|
25 + uint32_t index_size;
|
pascal@17266
|
26 + uint32_t num_blocks;
|
pascal@17266
|
27 +} cloop_tail;
|
pascal@17266
|
28 +
|
pascal@23680
|
29 +#define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF))
|
pascal@23680
|
30 +#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4)
|
pascal@23680
|
31 +
|
pascal@17266
|
32 +typedef struct block_info {
|
pascal@17266
|
33 + uint64_t offset; /* 64-bit offsets of compressed block */
|
pascal@17266
|
34 + uint32_t size; /* 32-bit compressed block size */
|
pascal@23680
|
35 + uint32_t flags; /* 32-bit compression flags */
|
pascal@17266
|
36 +} block_info;
|
pascal@17266
|
37 +
|
pascal@23680
|
38 +static inline int build_index(struct block_info *offsets, unsigned long n,
|
pascal@23680
|
39 + unsigned long block_size, unsigned global_flags)
|
pascal@17266
|
40 +{
|
pascal@17266
|
41 + uint32_t *ofs32 = (uint32_t *) offsets;
|
pascal@23680
|
42 + loff_t *ofs64 = (loff_t *) offsets;
|
pascal@23680
|
43 +
|
pascal@23680
|
44 + /* v3 64bits bug: v1 assumed */
|
pascal@23685
|
45 + unsigned long v3_64=(n+1)/2;
|
pascal@23680
|
46 + loff_t prev;
|
pascal@23680
|
47 +
|
pascal@23680
|
48 + if (ofs32[0] != 0 && ofs32[1] == 0) {
|
pascal@23685
|
49 + for (prev=le64_to_cpu(ofs64[v3_64]);
|
pascal@23680
|
50 + v3_64 > 0 && le64_to_cpu(ofs64[--v3_64]) < prev;
|
pascal@23680
|
51 + prev=le64_to_cpu(ofs64[v3_64]));
|
pascal@23680
|
52 + }
|
pascal@23680
|
53 +
|
pascal@17266
|
54 + if (ofs32[0] == 0) {
|
pascal@17266
|
55 + if (ofs32[2]) { /* ACCELERATED KNOPPIX V1.0 */
|
pascal@17266
|
56 + while (n--) {
|
pascal@17266
|
57 + offsets[n].offset = be64_to_cpu(offsets[n].offset);
|
pascal@23685
|
58 + offsets[n].size = be32_to_cpu(offsets[n].size);
|
pascal@23680
|
59 + offsets[n].flags = 0;
|
pascal@17989
|
60 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
61 + return n+1;
|
pascal@17266
|
62 + }
|
pascal@17266
|
63 + }
|
pascal@23680
|
64 + else { /* V2.0/V4.0 */
|
pascal@23680
|
65 + loff_t last = CLOOP_BLOCK_OFFSET(be64_to_cpu(ofs64[n]));
|
pascal@23680
|
66 + uint32_t flags;
|
pascal@23680
|
67 + unsigned long i = n;
|
pascal@23680
|
68 +
|
pascal@23680
|
69 + for (flags = 0; n-- ;) {
|
pascal@23680
|
70 + loff_t data = be64_to_cpu(ofs64[n]);
|
pascal@23680
|
71 +
|
pascal@17266
|
72 + offsets[n].size = last -
|
pascal@23680
|
73 + (offsets[n].offset = CLOOP_BLOCK_OFFSET(data));
|
pascal@17989
|
74 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
75 + return n+1;
|
pascal@17266
|
76 + last = offsets[n].offset;
|
pascal@23680
|
77 + offsets[n].flags = CLOOP_BLOCK_FLAGS(data);
|
pascal@23680
|
78 + flags |= 1 << offsets[n].flags;
|
pascal@23680
|
79 + }
|
pascal@23680
|
80 + if (flags > 1) {
|
pascal@23680
|
81 + while (i--) {
|
pascal@23680
|
82 + if (offsets[i].flags == CLOOP_COMPRESSOR_LINK) {
|
pascal@23680
|
83 + offsets[i] = offsets[offsets[i].offset];
|
pascal@23680
|
84 + }
|
pascal@23680
|
85 + }
|
pascal@17266
|
86 + }
|
pascal@17266
|
87 + }
|
pascal@17266
|
88 + }
|
pascal@23680
|
89 + else if (ofs32[1] == 0 && v3_64 == 0) { /* V1.0 */
|
pascal@23680
|
90 + loff_t last = le64_to_cpu(ofs64[n]);
|
pascal@17266
|
91 + while (n--) {
|
pascal@17266
|
92 + offsets[n].size = last -
|
pascal@17266
|
93 + (offsets[n].offset = le64_to_cpu(ofs64[n]));
|
pascal@17989
|
94 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
95 + return n+1;
|
pascal@17266
|
96 + last = offsets[n].offset;
|
pascal@23680
|
97 + offsets[n].flags = 0;
|
pascal@17266
|
98 + }
|
pascal@17266
|
99 + }
|
pascal@23685
|
100 + else if (be32_to_cpu(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */
|
pascal@23685
|
101 + loff_t last = be32_to_cpu(ofs32[n]);
|
pascal@17266
|
102 + while (n--) {
|
pascal@17266
|
103 + offsets[n].size = last -
|
pascal@23685
|
104 + (offsets[n].offset = be32_to_cpu(ofs32[n]));
|
pascal@17989
|
105 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
106 + return n+1;
|
pascal@17266
|
107 + last = offsets[n].offset;
|
pascal@23680
|
108 + offsets[n].flags = 0;
|
pascal@17266
|
109 + }
|
pascal@17266
|
110 + }
|
pascal@17266
|
111 + else { /* V3.0 */
|
pascal@17266
|
112 + unsigned long i;
|
pascal@23680
|
113 + loff_t j;
|
pascal@17266
|
114 +
|
pascal@23680
|
115 + v3_64 = (ofs32[1] == 0) ? 2 : 1;
|
pascal@17989
|
116 + for (i = n; i-- > 0; ) {
|
pascal@23685
|
117 + offsets[i].size = be32_to_cpu(ofs32[i*v3_64]);
|
pascal@23680
|
118 + if ((offsets[i].size & 0x80000000) == 0 &&
|
pascal@23680
|
119 + offsets[i].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
120 + return i+1;
|
pascal@17989
|
121 + }
|
pascal@17266
|
122 + for (i = 0, j = 128 + 4 + 4; i < n; i++) {
|
pascal@17266
|
123 + offsets[i].offset = j;
|
pascal@23680
|
124 + offsets[i].flags = global_flags;
|
pascal@23680
|
125 + if (offsets[i].size == 0xFFFFFFFF) {
|
pascal@23680
|
126 + offsets[i].flags = CLOOP_COMPRESSOR_NONE;
|
pascal@23680
|
127 + offsets[i].size = block_size;
|
pascal@23680
|
128 + }
|
pascal@23680
|
129 + if ((offsets[i].size & 0x80000000) == 0) {
|
pascal@23680
|
130 + j += offsets[i].size;
|
pascal@23680
|
131 + }
|
pascal@23680
|
132 + }
|
pascal@23680
|
133 + for (i = 0; i < n; i++) {
|
pascal@18828
|
134 + if (offsets[i].size & 0x80000000) {
|
pascal@23680
|
135 + offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF];
|
pascal@18828
|
136 + }
|
pascal@17266
|
137 + }
|
pascal@17266
|
138 + }
|
pascal@17989
|
139 + return 0;
|
pascal@17266
|
140 +}
|
pascal@17266
|
141 +
|
pascal@17266
|
142 typedef struct BDRVCloopState {
|
pascal@17266
|
143 CoMutex lock;
|
pascal@17266
|
144 uint32_t block_size;
|
pascal@17266
|
145 uint32_t n_blocks;
|
pascal@17266
|
146 - uint64_t *offsets;
|
pascal@17266
|
147 + block_info *offsets;
|
pascal@17266
|
148 uint32_t sectors_per_block;
|
pascal@17266
|
149 uint32_t current_block;
|
pascal@17266
|
150 uint8_t *compressed_block;
|
pascal@23680
|
151 uint8_t *uncompressed_block;
|
pascal@23680
|
152 z_stream zstream;
|
pascal@23680
|
153 + int global_flags;
|
pascal@23680
|
154 } BDRVCloopState;
|
pascal@17266
|
155
|
pascal@17266
|
156 static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
|
pascal@17266
|
157 {
|
pascal@17266
|
158 - const char *magic_version_2_0 = "#!/bin/sh\n"
|
pascal@17266
|
159 - "#V2.0 Format\n"
|
pascal@17266
|
160 + static const uint8_t magic[] =
|
pascal@17266
|
161 "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
|
pascal@17266
|
162 - int length = strlen(magic_version_2_0);
|
pascal@17266
|
163 - if (length > buf_size) {
|
pascal@17266
|
164 - length = buf_size;
|
pascal@23685
|
165 + int ret = 0, length = buf_size;
|
pascal@23685
|
166 + int i;
|
pascal@17266
|
167 +
|
pascal@17266
|
168 + if (length > 127) {
|
pascal@17266
|
169 + length = 127;
|
pascal@23680
|
170 + }
|
pascal@17266
|
171 + for (i = 0; i < length - sizeof(magic) + 1; i++) {
|
pascal@17266
|
172 + if (buf[i] != magic[0]) continue;
|
pascal@23685
|
173 + if (memcmp(buf + i, magic, sizeof(magic) - 1)) continue;
|
pascal@17266
|
174 + ret = 2;
|
pascal@17266
|
175 + break;
|
pascal@17266
|
176 }
|
pascal@23680
|
177 - if (!memcmp(magic_version_2_0, buf, length)) {
|
pascal@23680
|
178 - return 2;
|
pascal@17266
|
179 + return ret;
|
pascal@23680
|
180 +}
|
pascal@23680
|
181 +
|
pascal@23685
|
182 +static uint32_t cloop_unpack(BDRVCloopState *s, int flag)
|
pascal@23680
|
183 +{
|
pascal@23680
|
184 + int ret;
|
pascal@23680
|
185 + size_t src_pos;
|
pascal@23680
|
186 + size_t dest_pos;
|
pascal@23680
|
187 + uint64_t memlimit;
|
pascal@23766
|
188 + uint32_t outlen = s->zstream.avail_out;
|
pascal@23680
|
189 +
|
pascal@23680
|
190 + switch (flag) {
|
pascal@23680
|
191 + case CLOOP_COMPRESSOR_ZLIB:
|
pascal@23680
|
192 + ret = inflateReset(&s->zstream);
|
pascal@23680
|
193 + if (ret != Z_OK) {
|
pascal@23680
|
194 + return 0;
|
pascal@23680
|
195 + }
|
pascal@23680
|
196 + ret = inflate(&s->zstream, Z_FINISH);
|
pascal@23680
|
197 + if (ret != Z_STREAM_END || s->zstream.total_out != outlen) {
|
pascal@23680
|
198 + return 0;
|
pascal@23680
|
199 + }
|
pascal@23680
|
200 + return outlen;
|
pascal@23680
|
201 + case CLOOP_COMPRESSOR_NONE:
|
pascal@23680
|
202 + memcpy(s->zstream.next_out, s->zstream.next_in, s->zstream.avail_in);
|
pascal@23680
|
203 + return s->zstream.avail_in;
|
pascal@23680
|
204 + case CLOOP_COMPRESSOR_XZ:
|
pascal@23680
|
205 + src_pos = 0;
|
pascal@23680
|
206 + dest_pos = 0;
|
pascal@23680
|
207 + memlimit = 32*1024*1024;
|
pascal@23680
|
208 + ret = lzma_stream_buffer_decode(&memlimit, 0, NULL, s->zstream.next_in, &src_pos,
|
pascal@23680
|
209 + s->zstream.avail_in, s->zstream.next_out, &dest_pos, s->zstream.total_out);
|
pascal@23680
|
210 +
|
pascal@23680
|
211 + if(ret != LZMA_OK || s->zstream.avail_in != (int) src_pos) {
|
pascal@23680
|
212 + return 0;
|
pascal@23680
|
213 + }
|
pascal@23680
|
214 + return dest_pos;
|
pascal@23680
|
215 }
|
pascal@23680
|
216 return 0;
|
pascal@17266
|
217 }
|
pascal@23696
|
218 @@ -60,7 +233,7 @@
|
pascal@23696
|
219 Error **errp)
|
pascal@23696
|
220 {
|
pascal@23696
|
221 BDRVCloopState *s = bs->opaque;
|
pascal@23696
|
222 - uint32_t offsets_size, max_compressed_block_size = 1, i;
|
pascal@23696
|
223 + uint32_t offsets_size, max_compressed_block_size = 1;
|
pascal@23696
|
224 int ret;
|
pascal@23696
|
225
|
pascal@23696
|
226 bs->read_only = 1;
|
pascal@23680
|
227 @@ -91,79 +264,92 @@
|
pascal@17989
|
228 MAX_BLOCK_SIZE / (1024 * 1024));
|
pascal@17989
|
229 return -EINVAL;
|
pascal@17989
|
230 }
|
pascal@17989
|
231 -
|
pascal@17989
|
232 ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
pascal@17989
|
233 if (ret < 0) {
|
pascal@17989
|
234 return ret;
|
pascal@17266
|
235 }
|
pascal@17266
|
236 s->n_blocks = be32_to_cpu(s->n_blocks);
|
pascal@17266
|
237
|
pascal@17990
|
238 - /* read offsets */
|
pascal@17989
|
239 - if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
pascal@17990
|
240 - /* Prevent integer overflow */
|
pascal@17990
|
241 - error_setg(errp, "n_blocks %u must be %zu or less",
|
pascal@17990
|
242 - s->n_blocks,
|
pascal@17989
|
243 - (UINT32_MAX - 1) / sizeof(uint64_t));
|
pascal@17990
|
244 - return -EINVAL;
|
pascal@17990
|
245 - }
|
pascal@17989
|
246 - offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
|
pascal@17989
|
247 - if (offsets_size > 512 * 1024 * 1024) {
|
pascal@17989
|
248 - /* Prevent ridiculous offsets_size which causes memory allocation to
|
pascal@17989
|
249 - * fail or overflows bdrv_pread() size. In practice the 512 MB
|
pascal@17989
|
250 - * offsets[] limit supports 16 TB images at 256 KB block size.
|
pascal@17989
|
251 - */
|
pascal@17989
|
252 - error_setg(errp, "image requires too many offsets, "
|
pascal@17989
|
253 - "try increasing block size");
|
pascal@17989
|
254 - return -EINVAL;
|
pascal@17989
|
255 - }
|
pascal@17989
|
256 - s->offsets = g_malloc(offsets_size);
|
pascal@17990
|
257 + /* initialize zlib engine */
|
pascal@17990
|
258 + max_compressed_block_size = s->block_size + s->block_size/1000 + 12 + 4;
|
pascal@17990
|
259 + s->compressed_block = g_malloc(max_compressed_block_size + 1);
|
pascal@17990
|
260 + s->uncompressed_block = g_malloc(s->block_size);
|
pascal@17990
|
261
|
pascal@17990
|
262 - ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
pascal@17990
|
263 - if (ret < 0) {
|
pascal@17990
|
264 + if (inflateInit(&s->zstream) != Z_OK) {
|
pascal@17990
|
265 + ret = -EINVAL;
|
pascal@17990
|
266 goto fail;
|
pascal@17990
|
267 }
|
pascal@17990
|
268
|
pascal@17990
|
269 - for (i = 0; i < s->n_blocks + 1; i++) {
|
pascal@17990
|
270 - uint64_t size;
|
pascal@17990
|
271 + /* read offsets */
|
pascal@17266
|
272 + if (s->n_blocks + 1 == 0) {
|
pascal@17266
|
273 + cloop_tail tail;
|
pascal@17266
|
274 + int64_t end = bdrv_getlength(bs->file);
|
pascal@17266
|
275 + void *p;
|
pascal@17266
|
276 + uint32_t toclen, len;
|
pascal@17989
|
277
|
pascal@17990
|
278 - s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
pascal@17990
|
279 - if (i == 0) {
|
pascal@17990
|
280 - continue;
|
pascal@17266
|
281 + ret = bdrv_pread(bs->file, end - sizeof(tail), &tail, sizeof(tail));
|
pascal@17266
|
282 + if (ret < 0) {
|
pascal@17266
|
283 + goto fail;
|
pascal@17990
|
284 }
|
pascal@17989
|
285
|
pascal@17990
|
286 - if (s->offsets[i] < s->offsets[i - 1]) {
|
pascal@17990
|
287 - error_setg(errp, "offsets not monotonically increasing at "
|
pascal@17990
|
288 - "index %u, image file is corrupt", i);
|
pascal@17990
|
289 - ret = -EINVAL;
|
pascal@17990
|
290 - goto fail;
|
pascal@17266
|
291 + s->n_blocks = be32_to_cpu(tail.num_blocks);
|
pascal@17266
|
292 + offsets_size = s->n_blocks * sizeof(block_info);
|
pascal@17989
|
293 + if (offsets_size > 512 * 1024 * 1024) {
|
pascal@17989
|
294 + /* Prevent ridiculous offsets_size which causes memory allocation to
|
pascal@17989
|
295 + * fail or overflows bdrv_pread() size. In practice the 512 MB
|
pascal@17989
|
296 + * offsets[] limit supports 16 TB images at 256 KB block size.
|
pascal@17989
|
297 + */
|
pascal@17989
|
298 + error_setg(errp, "image requires too many offsets, "
|
pascal@17989
|
299 + "try increasing block size");
|
pascal@17989
|
300 + return -EINVAL;
|
pascal@17989
|
301 }
|
pascal@17266
|
302 + len = be32_to_cpu(tail.table_size);
|
pascal@23680
|
303 + toclen = CLOOP3_INDEX_SIZE(be32_to_cpu(tail.index_size)) * s->n_blocks;
|
pascal@23680
|
304 + s->global_flags = CLOOP3_BLOCKS_FLAGS(be32_to_cpu(tail.index_size));
|
pascal@17989
|
305
|
pascal@17990
|
306 - size = s->offsets[i] - s->offsets[i - 1];
|
pascal@17266
|
307 + s->offsets = g_malloc(offsets_size);
|
pascal@17266
|
308 + p = g_malloc(len);
|
pascal@17990
|
309
|
pascal@17990
|
310 - /* Compressed blocks should be smaller than the uncompressed block size
|
pascal@17990
|
311 - * but maybe compression performed poorly so the compressed block is
|
pascal@17990
|
312 - * actually bigger. Clamp down on unrealistic values to prevent
|
pascal@17990
|
313 - * ridiculous s->compressed_block allocation.
|
pascal@17990
|
314 - */
|
pascal@17990
|
315 - if (size > 2 * MAX_BLOCK_SIZE) {
|
pascal@17990
|
316 - error_setg(errp, "invalid compressed block size at index %u, "
|
pascal@17990
|
317 - "image file is corrupt", i);
|
pascal@17266
|
318 + ret = bdrv_pread(bs->file, end - sizeof(tail) - len, p, len);
|
pascal@17266
|
319 + if (ret < 0) {
|
pascal@17266
|
320 + goto fail;
|
pascal@17266
|
321 + }
|
pascal@17266
|
322 + s->zstream.next_in = p;
|
pascal@17266
|
323 + s->zstream.avail_in = len;
|
pascal@17266
|
324 + s->zstream.next_out = s->offsets;
|
pascal@17266
|
325 + s->zstream.avail_out = toclen;
|
pascal@23680
|
326 + if (cloop_unpack(s, s->global_flags) == 0) {
|
pascal@17989
|
327 ret = -EINVAL;
|
pascal@17989
|
328 goto fail;
|
pascal@17989
|
329 }
|
pascal@17266
|
330 + g_free(p);
|
pascal@23680
|
331 + }
|
pascal@17266
|
332 + else {
|
pascal@17266
|
333 + offsets_size = s->n_blocks * sizeof(block_info);
|
pascal@17989
|
334 + if (offsets_size > 512 * 1024 * 1024) {
|
pascal@17989
|
335 + /* Prevent ridiculous offsets_size which causes memory allocation to
|
pascal@17989
|
336 + * fail or overflows bdrv_pread() size. In practice the 512 MB
|
pascal@17989
|
337 + * offsets[] limit supports 16 TB images at 256 KB block size.
|
pascal@17989
|
338 + */
|
pascal@17989
|
339 + error_setg(errp, "image requires too many offsets, "
|
pascal@17989
|
340 + "try increasing block size");
|
pascal@17989
|
341 + return -EINVAL;
|
pascal@17989
|
342 + }
|
pascal@17266
|
343 + s->offsets = g_malloc(offsets_size);
|
pascal@17266
|
344
|
pascal@23680
|
345 - if (size > max_compressed_block_size) {
|
pascal@23680
|
346 - max_compressed_block_size = size;
|
pascal@23680
|
347 + ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
pascal@23680
|
348 + if (ret < 0) {
|
pascal@23680
|
349 + goto fail;
|
pascal@23680
|
350 }
|
pascal@23680
|
351 }
|
pascal@23680
|
352 -
|
pascal@17266
|
353 - /* initialize zlib engine */
|
pascal@17266
|
354 - s->compressed_block = g_malloc(max_compressed_block_size + 1);
|
pascal@17266
|
355 - s->uncompressed_block = g_malloc(s->block_size);
|
pascal@17266
|
356 - if (inflateInit(&s->zstream) != Z_OK) {
|
pascal@23680
|
357 + ret = build_index(s->offsets, s->n_blocks, s->block_size, s->global_flags);
|
pascal@17989
|
358 + if (ret) {
|
pascal@17989
|
359 + error_setg(errp, "invalid compressed block size at index %u, "
|
pascal@17989
|
360 + "image file is corrupt", ret-1);
|
pascal@17989
|
361 ret = -EINVAL;
|
pascal@17989
|
362 goto fail;
|
pascal@17266
|
363 }
|
pascal@17266
|
364 +
|
pascal@17266
|
365 s->current_block = s->n_blocks;
|
pascal@17266
|
366
|
pascal@17266
|
367 s->sectors_per_block = s->block_size/512;
|
pascal@23680
|
368 @@ -184,10 +370,10 @@
|
pascal@17266
|
369
|
pascal@17266
|
370 if (s->current_block != block_num) {
|
pascal@17266
|
371 int ret;
|
pascal@17266
|
372 - uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
|
pascal@17266
|
373 + uint32_t bytes = s->offsets[block_num].size;
|
pascal@17266
|
374
|
pascal@17266
|
375 - ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
|
pascal@17266
|
376 - bytes);
|
pascal@17266
|
377 + ret = bdrv_pread(bs->file, s->offsets[block_num].offset,
|
pascal@17266
|
378 + s->compressed_block, bytes);
|
pascal@17266
|
379 if (ret != bytes) {
|
pascal@17266
|
380 return -1;
|
pascal@17266
|
381 }
|
pascal@23680
|
382 @@ -196,12 +382,7 @@
|
pascal@23680
|
383 s->zstream.avail_in = bytes;
|
pascal@23680
|
384 s->zstream.next_out = s->uncompressed_block;
|
pascal@23680
|
385 s->zstream.avail_out = s->block_size;
|
pascal@23680
|
386 - ret = inflateReset(&s->zstream);
|
pascal@23680
|
387 - if (ret != Z_OK) {
|
pascal@23680
|
388 - return -1;
|
pascal@23680
|
389 - }
|
pascal@23680
|
390 - ret = inflate(&s->zstream, Z_FINISH);
|
pascal@23680
|
391 - if (ret != Z_STREAM_END || s->zstream.total_out != s->block_size) {
|
pascal@23680
|
392 + if (cloop_unpack(s, s->offsets[block_num].flags) == 0) {
|
pascal@23680
|
393 return -1;
|
pascal@23680
|
394 }
|
pascal@23680
|
395
|
pascal@23682
|
396 --- block/Makefile.objs
|
pascal@23682
|
397 +++ block/Makefile.objs
|
pascal@23680
|
398 @@ -35,5 +35,5 @@
|
pascal@23680
|
399 gluster.o-libs := $(GLUSTERFS_LIBS)
|
pascal@23680
|
400 ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
pascal@23680
|
401 ssh.o-libs := $(LIBSSH2_LIBS)
|
pascal@23680
|
402 -qcow.o-libs := -lz
|
pascal@23680
|
403 +qcow.o-libs := -lz -llzma
|
pascal@23680
|
404 linux-aio.o-libs := -laio
|
pascal@23762
|
405 --- block/cloop.c
|
pascal@23762
|
406 +++ block/cloop.c
|
pascal@23762
|
407 @@ -48,7 +48,6 @@
|
pascal@23762
|
408 } cloop_tail;
|
pascal@23762
|
409
|
pascal@23762
|
410 #define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF))
|
pascal@23762
|
411 -#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4)
|
pascal@23762
|
412
|
pascal@23762
|
413 typedef struct block_info {
|
pascal@23762
|
414 uint64_t offset; /* 64-bit offsets of compressed block */
|
pascal@23762
|
415 @@ -57,7 +56,7 @@
|
pascal@23762
|
416 } block_info;
|
pascal@23762
|
417
|
pascal@23762
|
418 static inline int build_index(struct block_info *offsets, unsigned long n,
|
pascal@23762
|
419 - unsigned long block_size, unsigned global_flags)
|
pascal@23762
|
420 + unsigned long block_size)
|
pascal@23762
|
421 {
|
pascal@23762
|
422 uint32_t *ofs32 = (uint32_t *) offsets;
|
pascal@23762
|
423 loff_t *ofs64 = (loff_t *) offsets;
|
pascal@23762
|
424 @@ -118,42 +117,44 @@
|
pascal@23762
|
425 offsets[n].flags = 0;
|
pascal@23762
|
426 }
|
pascal@23762
|
427 }
|
pascal@23762
|
428 - else if (be32_to_cpu(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */
|
pascal@23762
|
429 - loff_t last = be32_to_cpu(ofs32[n]);
|
pascal@23762
|
430 - while (n--) {
|
pascal@23762
|
431 - offsets[n].size = last -
|
pascal@23762
|
432 - (offsets[n].offset = be32_to_cpu(ofs32[n]));
|
pascal@23762
|
433 - if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@23762
|
434 - return n+1;
|
pascal@23762
|
435 - last = offsets[n].offset;
|
pascal@23762
|
436 - offsets[n].flags = 0;
|
pascal@23762
|
437 - }
|
pascal@23762
|
438 - }
|
pascal@23762
|
439 - else { /* V3.0 */
|
pascal@23762
|
440 + else { /* V3.0 or V0.68 */
|
pascal@23762
|
441 unsigned long i;
|
pascal@23762
|
442 loff_t j;
|
pascal@23762
|
443
|
pascal@23762
|
444 - v3_64 = (ofs32[1] == 0) ? 2 : 1;
|
pascal@23762
|
445 + for (i = 0; i < n && be32_to_cpu(ofs32[i]) < be32_to_cpu(ofs32[i+1]); i++);
|
pascal@23762
|
446 + if (i == n && be32_to_cpu(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */
|
pascal@23762
|
447 + loff_t last = be32_to_cpu(ofs32[n]);
|
pascal@23762
|
448 + while (n--) {
|
pascal@23762
|
449 + offsets[n].size = last -
|
pascal@23762
|
450 + (offsets[n].offset = be32_to_cpu(ofs32[n]));
|
pascal@23762
|
451 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@23762
|
452 + return n+1;
|
pascal@23762
|
453 + last = offsets[n].offset;
|
pascal@23762
|
454 + offsets[n].flags = 0;
|
pascal@23762
|
455 + }
|
pascal@23762
|
456 + return 0;
|
pascal@23762
|
457 + }
|
pascal@23762
|
458 +
|
pascal@23762
|
459 + v3_64 = (ofs32[1] == 0);
|
pascal@23762
|
460 for (i = n; i-- > 0; ) {
|
pascal@23762
|
461 - offsets[i].size = be32_to_cpu(ofs32[i*v3_64]);
|
pascal@23762
|
462 - if ((offsets[i].size & 0x80000000) == 0 &&
|
pascal@23762
|
463 - offsets[i].size > 2 * MAX_BLOCK_SIZE)
|
pascal@23762
|
464 + offsets[i].size = be32_to_cpu(ofs32[i << v3_64]);
|
pascal@23762
|
465 + if (offsets[i].size == 0xFFFFFFFF) {
|
pascal@23762
|
466 + offsets[i].size = 0x10000000 | block_size;
|
pascal@23762
|
467 + }
|
pascal@23762
|
468 + offsets[i].flags = (offsets[i].size >> 28);
|
pascal@23762
|
469 + offsets[i].size &= 0x0FFFFFFF;
|
pascal@23762
|
470 + if (offsets[i].size > 2 * MAX_BLOCK_SIZE)
|
pascal@23762
|
471 return i+1;
|
pascal@23762
|
472 }
|
pascal@23762
|
473 for (i = 0, j = 128 + 4 + 4; i < n; i++) {
|
pascal@23762
|
474 offsets[i].offset = j;
|
pascal@23762
|
475 - offsets[i].flags = global_flags;
|
pascal@23762
|
476 - if (offsets[i].size == 0xFFFFFFFF) {
|
pascal@23762
|
477 - offsets[i].flags = CLOOP_COMPRESSOR_NONE;
|
pascal@23762
|
478 - offsets[i].size = block_size;
|
pascal@23762
|
479 - }
|
pascal@23762
|
480 - if ((offsets[i].size & 0x80000000) == 0) {
|
pascal@23762
|
481 + if (offsets[i].flags < 8) {
|
pascal@23762
|
482 j += offsets[i].size;
|
pascal@23762
|
483 }
|
pascal@23762
|
484 }
|
pascal@23762
|
485 for (i = 0; i < n; i++) {
|
pascal@23762
|
486 - if (offsets[i].size & 0x80000000) {
|
pascal@23762
|
487 - offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF];
|
pascal@23762
|
488 + if (offsets[i].flags >= 8) {
|
pascal@23762
|
489 + offsets[i] = offsets[offsets[i].size];
|
pascal@23762
|
490 }
|
pascal@23762
|
491 }
|
pascal@23762
|
492 }
|
pascal@23762
|
493 @@ -170,7 +171,6 @@
|
pascal@23762
|
494 uint8_t *compressed_block;
|
pascal@23762
|
495 uint8_t *uncompressed_block;
|
pascal@23762
|
496 z_stream zstream;
|
pascal@23762
|
497 - int global_flags;
|
pascal@23762
|
498 } BDRVCloopState;
|
pascal@23762
|
499
|
pascal@23762
|
500 static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
|
pascal@23762
|
501 @@ -305,7 +305,6 @@
|
pascal@23762
|
502 }
|
pascal@23762
|
503 len = be32_to_cpu(tail.table_size);
|
pascal@23762
|
504 toclen = CLOOP3_INDEX_SIZE(be32_to_cpu(tail.index_size)) * s->n_blocks;
|
pascal@23762
|
505 - s->global_flags = CLOOP3_BLOCKS_FLAGS(be32_to_cpu(tail.index_size));
|
pascal@23762
|
506
|
pascal@23762
|
507 s->offsets = g_malloc(offsets_size);
|
pascal@23762
|
508 p = g_malloc(len);
|
pascal@23762
|
509 @@ -316,9 +315,9 @@
|
pascal@23762
|
510 }
|
pascal@23762
|
511 s->zstream.next_in = p;
|
pascal@23762
|
512 s->zstream.avail_in = len;
|
pascal@23762
|
513 - s->zstream.next_out = s->offsets;
|
pascal@23762
|
514 + s->zstream.next_out = (void *) s->offsets;
|
pascal@23762
|
515 s->zstream.avail_out = toclen;
|
pascal@23762
|
516 - if (cloop_unpack(s, s->global_flags) == 0) {
|
pascal@23762
|
517 + if (cloop_unpack(s, CLOOP_COMPRESSOR_ZLIB) == 0) {
|
pascal@23762
|
518 ret = -EINVAL;
|
pascal@23762
|
519 goto fail;
|
pascal@23762
|
520 }
|
pascal@23762
|
521 @@ -342,7 +341,7 @@
|
pascal@23762
|
522 goto fail;
|
pascal@23762
|
523 }
|
pascal@23762
|
524 }
|
pascal@23762
|
525 - ret = build_index(s->offsets, s->n_blocks, s->block_size, s->global_flags);
|
pascal@23762
|
526 + ret = build_index(s->offsets, s->n_blocks, s->block_size);
|
pascal@23762
|
527 if (ret) {
|
pascal@23762
|
528 error_setg(errp, "invalid compressed block size at index %u, "
|
pascal@23762
|
529 "image file is corrupt", ret-1);
|