rev |
line source |
pascal@17266
|
1 --- block/cloop.c
|
pascal@17266
|
2 +++ block/cloop.c
|
pascal@18828
|
3 @@ -29,11 +29,90 @@
|
pascal@17989
|
4 /* Maximum compressed block size */
|
pascal@17989
|
5 #define MAX_BLOCK_SIZE (64 * 1024 * 1024)
|
pascal@17266
|
6
|
pascal@17266
|
7 +typedef struct cloop_tail {
|
pascal@17266
|
8 + uint32_t table_size;
|
pascal@17266
|
9 + uint32_t index_size;
|
pascal@17266
|
10 + uint32_t num_blocks;
|
pascal@17266
|
11 +} cloop_tail;
|
pascal@17266
|
12 +
|
pascal@17266
|
13 +typedef struct block_info {
|
pascal@17266
|
14 + uint64_t offset; /* 64-bit offsets of compressed block */
|
pascal@17266
|
15 + uint32_t size; /* 32-bit compressed block size */
|
pascal@17266
|
16 + uint32_t optidx; /* 32-bit index number */
|
pascal@17266
|
17 +} block_info;
|
pascal@17266
|
18 +
|
pascal@17989
|
19 +static inline int build_index(block_info *offsets, unsigned long n)
|
pascal@17266
|
20 +{
|
pascal@17266
|
21 + uint32_t *ofs32 = (uint32_t *) offsets;
|
pascal@17266
|
22 + uint64_t *ofs64 = (uint64_t *) offsets;
|
pascal@17266
|
23 +
|
pascal@17266
|
24 + if (ofs32[0] == 0) {
|
pascal@17266
|
25 + if (ofs32[2]) { /* ACCELERATED KNOPPIX V1.0 */
|
pascal@17266
|
26 + while (n--) {
|
pascal@17266
|
27 + offsets[n].offset = be64_to_cpu(offsets[n].offset);
|
pascal@17266
|
28 + offsets[n].size = ntohl(offsets[n].size);
|
pascal@17989
|
29 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
30 + return n+1;
|
pascal@17266
|
31 + }
|
pascal@17266
|
32 + }
|
pascal@17266
|
33 + else { /* V2.0 */
|
pascal@17442
|
34 + uint64_t last = be64_to_cpu(ofs64[n - 1]);
|
pascal@17266
|
35 + while (n--) {
|
pascal@17266
|
36 + offsets[n].size = last -
|
pascal@17266
|
37 + (offsets[n].offset = be64_to_cpu(ofs64[n]));
|
pascal@17989
|
38 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
39 + return n+1;
|
pascal@17266
|
40 + last = offsets[n].offset;
|
pascal@17266
|
41 + }
|
pascal@17266
|
42 + }
|
pascal@17266
|
43 + }
|
pascal@17266
|
44 + else if (ofs32[1] == 0) { /* V1.0 */
|
pascal@17442
|
45 + uint64_t last = le64_to_cpu(ofs64[n - 1]);
|
pascal@17266
|
46 + while (n--) {
|
pascal@17266
|
47 + offsets[n].size = last -
|
pascal@17266
|
48 + (offsets[n].offset = le64_to_cpu(ofs64[n]));
|
pascal@17989
|
49 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
50 + return n+1;
|
pascal@17266
|
51 + last = offsets[n].offset;
|
pascal@17266
|
52 + }
|
pascal@17266
|
53 + }
|
pascal@17266
|
54 + else if (ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */
|
pascal@17442
|
55 + uint64_t last = ntohl(ofs32[n - 1]);
|
pascal@17266
|
56 + while (n--) {
|
pascal@17266
|
57 + offsets[n].size = last -
|
pascal@17266
|
58 + (offsets[n].offset = ntohl(ofs32[n]));
|
pascal@17989
|
59 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
60 + return n+1;
|
pascal@17266
|
61 + last = offsets[n].offset;
|
pascal@17266
|
62 + }
|
pascal@17266
|
63 + }
|
pascal@17266
|
64 + else { /* V3.0 */
|
pascal@17266
|
65 + unsigned long i;
|
pascal@17266
|
66 + uint64_t j;
|
pascal@17266
|
67 +
|
pascal@17989
|
68 + for (i = n; i-- > 0; ) {
|
pascal@17266
|
69 + offsets[i].size = ntohl(ofs32[i]);
|
pascal@17989
|
70 + if (offsets[i].size > 2 * MAX_BLOCK_SIZE)
|
pascal@17989
|
71 + return i+1;
|
pascal@17989
|
72 + }
|
pascal@17266
|
73 + for (i = 0, j = 128 + 4 + 4; i < n; i++) {
|
pascal@17266
|
74 + offsets[i].offset = j;
|
pascal@18828
|
75 + if (offsets[i].size & 0x80000000) {
|
pascal@18828
|
76 + unsigned long k = offset[i].size & 0x7FFFFFFF;
|
pascal@18828
|
77 + offsets[i].offset = offsets[k].offset;
|
pascal@18828
|
78 + offsets[i].size = offsets[k].size;
|
pascal@18828
|
79 + }
|
pascal@18828
|
80 + else j += offsets[i].size;
|
pascal@17266
|
81 + }
|
pascal@17266
|
82 + }
|
pascal@17989
|
83 + return 0;
|
pascal@17266
|
84 +}
|
pascal@17266
|
85 +
|
pascal@17266
|
86 typedef struct BDRVCloopState {
|
pascal@17266
|
87 CoMutex lock;
|
pascal@17266
|
88 uint32_t block_size;
|
pascal@17266
|
89 uint32_t n_blocks;
|
pascal@17266
|
90 - uint64_t *offsets;
|
pascal@17266
|
91 + block_info *offsets;
|
pascal@17266
|
92 uint32_t sectors_per_block;
|
pascal@17266
|
93 uint32_t current_block;
|
pascal@17266
|
94 uint8_t *compressed_block;
|
pascal@17989
|
95 @@ -43,17 +117,21 @@
|
pascal@17266
|
96
|
pascal@17266
|
97 static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
|
pascal@17266
|
98 {
|
pascal@17266
|
99 - const char *magic_version_2_0 = "#!/bin/sh\n"
|
pascal@17266
|
100 - "#V2.0 Format\n"
|
pascal@17266
|
101 + static const uint8_t magic[] =
|
pascal@17266
|
102 "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
|
pascal@17266
|
103 - int length = strlen(magic_version_2_0);
|
pascal@17266
|
104 - if (length > buf_size) {
|
pascal@17266
|
105 - length = buf_size;
|
pascal@17266
|
106 + int i, ret = 0, length = buf_size;
|
pascal@17266
|
107 + uint8_t c;
|
pascal@17266
|
108 +
|
pascal@17266
|
109 + if (length > 127) {
|
pascal@17266
|
110 + length = 127;
|
pascal@17266
|
111 }
|
pascal@17266
|
112 - if (!memcmp(magic_version_2_0, buf, length)) {
|
pascal@17266
|
113 - return 2;
|
pascal@17266
|
114 + for (i = 0; i < length - sizeof(magic) + 1; i++) {
|
pascal@17266
|
115 + if (buf[i] != magic[0]) continue;
|
pascal@17266
|
116 + if (strncmp(buf + i, magic, sizeof(magic) - 1)) continue;
|
pascal@17266
|
117 + ret = 2;
|
pascal@17266
|
118 + break;
|
pascal@17266
|
119 }
|
pascal@17266
|
120 - return 0;
|
pascal@17266
|
121 + return ret;
|
pascal@17266
|
122 }
|
pascal@17266
|
123
|
pascal@17989
|
124 static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
pascal@17990
|
125 @@ -91,79 +169,97 @@
|
pascal@17989
|
126 MAX_BLOCK_SIZE / (1024 * 1024));
|
pascal@17989
|
127 return -EINVAL;
|
pascal@17989
|
128 }
|
pascal@17989
|
129 -
|
pascal@17989
|
130 ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
pascal@17989
|
131 if (ret < 0) {
|
pascal@17989
|
132 return ret;
|
pascal@17266
|
133 }
|
pascal@17266
|
134 s->n_blocks = be32_to_cpu(s->n_blocks);
|
pascal@17266
|
135
|
pascal@17990
|
136 - /* read offsets */
|
pascal@17989
|
137 - if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
pascal@17990
|
138 - /* Prevent integer overflow */
|
pascal@17990
|
139 - error_setg(errp, "n_blocks %u must be %zu or less",
|
pascal@17990
|
140 - s->n_blocks,
|
pascal@17989
|
141 - (UINT32_MAX - 1) / sizeof(uint64_t));
|
pascal@17990
|
142 - return -EINVAL;
|
pascal@17990
|
143 - }
|
pascal@17989
|
144 - offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
|
pascal@17989
|
145 - if (offsets_size > 512 * 1024 * 1024) {
|
pascal@17989
|
146 - /* Prevent ridiculous offsets_size which causes memory allocation to
|
pascal@17989
|
147 - * fail or overflows bdrv_pread() size. In practice the 512 MB
|
pascal@17989
|
148 - * offsets[] limit supports 16 TB images at 256 KB block size.
|
pascal@17989
|
149 - */
|
pascal@17989
|
150 - error_setg(errp, "image requires too many offsets, "
|
pascal@17989
|
151 - "try increasing block size");
|
pascal@17989
|
152 - return -EINVAL;
|
pascal@17989
|
153 - }
|
pascal@17989
|
154 - s->offsets = g_malloc(offsets_size);
|
pascal@17990
|
155 + /* initialize zlib engine */
|
pascal@17990
|
156 + max_compressed_block_size = s->block_size + s->block_size/1000 + 12 + 4;
|
pascal@17990
|
157 + s->compressed_block = g_malloc(max_compressed_block_size + 1);
|
pascal@17990
|
158 + s->uncompressed_block = g_malloc(s->block_size);
|
pascal@17990
|
159
|
pascal@17990
|
160 - ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
pascal@17990
|
161 - if (ret < 0) {
|
pascal@17990
|
162 + if (inflateInit(&s->zstream) != Z_OK) {
|
pascal@17990
|
163 + ret = -EINVAL;
|
pascal@17990
|
164 goto fail;
|
pascal@17990
|
165 }
|
pascal@17990
|
166
|
pascal@17990
|
167 - for (i = 0; i < s->n_blocks + 1; i++) {
|
pascal@17990
|
168 - uint64_t size;
|
pascal@17990
|
169 + /* read offsets */
|
pascal@17266
|
170 + if (s->n_blocks + 1 == 0) {
|
pascal@17266
|
171 + cloop_tail tail;
|
pascal@17266
|
172 + int64_t end = bdrv_getlength(bs->file);
|
pascal@17266
|
173 + void *p;
|
pascal@17266
|
174 + uint32_t toclen, len;
|
pascal@17989
|
175
|
pascal@17990
|
176 - s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
pascal@17990
|
177 - if (i == 0) {
|
pascal@17990
|
178 - continue;
|
pascal@17266
|
179 + ret = bdrv_pread(bs->file, end - sizeof(tail), &tail, sizeof(tail));
|
pascal@17266
|
180 + if (ret < 0) {
|
pascal@17266
|
181 + goto fail;
|
pascal@17990
|
182 }
|
pascal@17989
|
183
|
pascal@17990
|
184 - if (s->offsets[i] < s->offsets[i - 1]) {
|
pascal@17990
|
185 - error_setg(errp, "offsets not monotonically increasing at "
|
pascal@17990
|
186 - "index %u, image file is corrupt", i);
|
pascal@17990
|
187 - ret = -EINVAL;
|
pascal@17990
|
188 - goto fail;
|
pascal@17266
|
189 + s->n_blocks = be32_to_cpu(tail.num_blocks);
|
pascal@17266
|
190 + offsets_size = s->n_blocks * sizeof(block_info);
|
pascal@17989
|
191 + if (offsets_size > 512 * 1024 * 1024) {
|
pascal@17989
|
192 + /* Prevent ridiculous offsets_size which causes memory allocation to
|
pascal@17989
|
193 + * fail or overflows bdrv_pread() size. In practice the 512 MB
|
pascal@17989
|
194 + * offsets[] limit supports 16 TB images at 256 KB block size.
|
pascal@17989
|
195 + */
|
pascal@17989
|
196 + error_setg(errp, "image requires too many offsets, "
|
pascal@17989
|
197 + "try increasing block size");
|
pascal@17989
|
198 + return -EINVAL;
|
pascal@17989
|
199 }
|
pascal@17266
|
200 + len = be32_to_cpu(tail.table_size);
|
pascal@17266
|
201 + toclen = (be32_to_cpu(tail.index_size) & 255) * s->n_blocks;
|
pascal@17989
|
202
|
pascal@17990
|
203 - size = s->offsets[i] - s->offsets[i - 1];
|
pascal@17266
|
204 + s->offsets = g_malloc(offsets_size);
|
pascal@17266
|
205 + p = g_malloc(len);
|
pascal@17990
|
206
|
pascal@17990
|
207 - /* Compressed blocks should be smaller than the uncompressed block size
|
pascal@17990
|
208 - * but maybe compression performed poorly so the compressed block is
|
pascal@17990
|
209 - * actually bigger. Clamp down on unrealistic values to prevent
|
pascal@17990
|
210 - * ridiculous s->compressed_block allocation.
|
pascal@17990
|
211 - */
|
pascal@17990
|
212 - if (size > 2 * MAX_BLOCK_SIZE) {
|
pascal@17990
|
213 - error_setg(errp, "invalid compressed block size at index %u, "
|
pascal@17990
|
214 - "image file is corrupt", i);
|
pascal@17266
|
215 + ret = bdrv_pread(bs->file, end - sizeof(tail) - len, p, len);
|
pascal@17266
|
216 + if (ret < 0) {
|
pascal@17266
|
217 + goto fail;
|
pascal@17266
|
218 + }
|
pascal@17266
|
219 + s->zstream.next_in = p;
|
pascal@17266
|
220 + s->zstream.avail_in = len;
|
pascal@17266
|
221 + s->zstream.next_out = s->offsets;
|
pascal@17266
|
222 + s->zstream.avail_out = toclen;
|
pascal@17266
|
223 + ret = inflateReset(&s->zstream);
|
pascal@17266
|
224 + if (ret != Z_OK) {
|
pascal@17989
|
225 ret = -EINVAL;
|
pascal@17989
|
226 goto fail;
|
pascal@17989
|
227 }
|
pascal@17989
|
228 -
|
pascal@17990
|
229 - if (size > max_compressed_block_size) {
|
pascal@17990
|
230 - max_compressed_block_size = size;
|
pascal@17266
|
231 + ret = inflate(&s->zstream, Z_FINISH);
|
pascal@17266
|
232 + if (ret != Z_STREAM_END || s->zstream.total_out != toclen) {
|
pascal@17990
|
233 + ret = -EINVAL;
|
pascal@17990
|
234 + goto fail;
|
pascal@17989
|
235 }
|
pascal@17266
|
236 + g_free(p);
|
pascal@17990
|
237 }
|
pascal@17266
|
238 + else {
|
pascal@17266
|
239 + offsets_size = s->n_blocks * sizeof(block_info);
|
pascal@17989
|
240 + if (offsets_size > 512 * 1024 * 1024) {
|
pascal@17989
|
241 + /* Prevent ridiculous offsets_size which causes memory allocation to
|
pascal@17989
|
242 + * fail or overflows bdrv_pread() size. In practice the 512 MB
|
pascal@17989
|
243 + * offsets[] limit supports 16 TB images at 256 KB block size.
|
pascal@17989
|
244 + */
|
pascal@17989
|
245 + error_setg(errp, "image requires too many offsets, "
|
pascal@17989
|
246 + "try increasing block size");
|
pascal@17989
|
247 + return -EINVAL;
|
pascal@17989
|
248 + }
|
pascal@17266
|
249 + s->offsets = g_malloc(offsets_size);
|
pascal@17266
|
250
|
pascal@17266
|
251 - /* initialize zlib engine */
|
pascal@17266
|
252 - s->compressed_block = g_malloc(max_compressed_block_size + 1);
|
pascal@17266
|
253 - s->uncompressed_block = g_malloc(s->block_size);
|
pascal@17266
|
254 - if (inflateInit(&s->zstream) != Z_OK) {
|
pascal@17990
|
255 + ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
pascal@17990
|
256 + if (ret < 0) {
|
pascal@17990
|
257 + goto fail;
|
pascal@17990
|
258 + }
|
pascal@17990
|
259 + }
|
pascal@17989
|
260 + ret = build_index(s->offsets, s->n_blocks);
|
pascal@17989
|
261 + if (ret) {
|
pascal@17989
|
262 + error_setg(errp, "invalid compressed block size at index %u, "
|
pascal@17989
|
263 + "image file is corrupt", ret-1);
|
pascal@17989
|
264 ret = -EINVAL;
|
pascal@17989
|
265 goto fail;
|
pascal@17266
|
266 }
|
pascal@17266
|
267 +
|
pascal@17266
|
268 s->current_block = s->n_blocks;
|
pascal@17266
|
269
|
pascal@17266
|
270 s->sectors_per_block = s->block_size/512;
|
pascal@17990
|
271 @@ -184,10 +280,10 @@
|
pascal@17266
|
272
|
pascal@17266
|
273 if (s->current_block != block_num) {
|
pascal@17266
|
274 int ret;
|
pascal@17266
|
275 - uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
|
pascal@17266
|
276 + uint32_t bytes = s->offsets[block_num].size;
|
pascal@17266
|
277
|
pascal@17266
|
278 - ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
|
pascal@17266
|
279 - bytes);
|
pascal@17266
|
280 + ret = bdrv_pread(bs->file, s->offsets[block_num].offset,
|
pascal@17266
|
281 + s->compressed_block, bytes);
|
pascal@17266
|
282 if (ret != bytes) {
|
pascal@17266
|
283 return -1;
|
pascal@17266
|
284 }
|