wok annotate qemu/stuff/cloop.u @ rev 17990

qemu: apply cloop.u (again)
author Pascal Bellard <pascal.bellard@slitaz.org>
date Thu Apr 23 15:15:23 2015 +0200 (2015-04-23)
parents 9c8ef3fd3dcf
children 8fe10eb4f215
rev   line source
pascal@17266 1 --- block/cloop.c
pascal@17266 2 +++ block/cloop.c
pascal@17989 3 @@ -29,11 +29,85 @@
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@17266 75 + j += offsets[i].size;
pascal@17266 76 + }
pascal@17266 77 + }
pascal@17989 78 + return 0;
pascal@17266 79 +}
pascal@17266 80 +
pascal@17266 81 typedef struct BDRVCloopState {
pascal@17266 82 CoMutex lock;
pascal@17266 83 uint32_t block_size;
pascal@17266 84 uint32_t n_blocks;
pascal@17266 85 - uint64_t *offsets;
pascal@17266 86 + block_info *offsets;
pascal@17266 87 uint32_t sectors_per_block;
pascal@17266 88 uint32_t current_block;
pascal@17266 89 uint8_t *compressed_block;
pascal@17989 90 @@ -43,17 +117,21 @@
pascal@17266 91
pascal@17266 92 static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
pascal@17266 93 {
pascal@17266 94 - const char *magic_version_2_0 = "#!/bin/sh\n"
pascal@17266 95 - "#V2.0 Format\n"
pascal@17266 96 + static const uint8_t magic[] =
pascal@17266 97 "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
pascal@17266 98 - int length = strlen(magic_version_2_0);
pascal@17266 99 - if (length > buf_size) {
pascal@17266 100 - length = buf_size;
pascal@17266 101 + int i, ret = 0, length = buf_size;
pascal@17266 102 + uint8_t c;
pascal@17266 103 +
pascal@17266 104 + if (length > 127) {
pascal@17266 105 + length = 127;
pascal@17266 106 }
pascal@17266 107 - if (!memcmp(magic_version_2_0, buf, length)) {
pascal@17266 108 - return 2;
pascal@17266 109 + for (i = 0; i < length - sizeof(magic) + 1; i++) {
pascal@17266 110 + if (buf[i] != magic[0]) continue;
pascal@17266 111 + if (strncmp(buf + i, magic, sizeof(magic) - 1)) continue;
pascal@17266 112 + ret = 2;
pascal@17266 113 + break;
pascal@17266 114 }
pascal@17266 115 - return 0;
pascal@17266 116 + return ret;
pascal@17266 117 }
pascal@17266 118
pascal@17989 119 static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
pascal@17990 120 @@ -91,79 +169,97 @@
pascal@17989 121 MAX_BLOCK_SIZE / (1024 * 1024));
pascal@17989 122 return -EINVAL;
pascal@17989 123 }
pascal@17989 124 -
pascal@17989 125 ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
pascal@17989 126 if (ret < 0) {
pascal@17989 127 return ret;
pascal@17266 128 }
pascal@17266 129 s->n_blocks = be32_to_cpu(s->n_blocks);
pascal@17266 130
pascal@17990 131 - /* read offsets */
pascal@17989 132 - if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
pascal@17990 133 - /* Prevent integer overflow */
pascal@17990 134 - error_setg(errp, "n_blocks %u must be %zu or less",
pascal@17990 135 - s->n_blocks,
pascal@17989 136 - (UINT32_MAX - 1) / sizeof(uint64_t));
pascal@17990 137 - return -EINVAL;
pascal@17990 138 - }
pascal@17989 139 - offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
pascal@17989 140 - if (offsets_size > 512 * 1024 * 1024) {
pascal@17989 141 - /* Prevent ridiculous offsets_size which causes memory allocation to
pascal@17989 142 - * fail or overflows bdrv_pread() size. In practice the 512 MB
pascal@17989 143 - * offsets[] limit supports 16 TB images at 256 KB block size.
pascal@17989 144 - */
pascal@17989 145 - error_setg(errp, "image requires too many offsets, "
pascal@17989 146 - "try increasing block size");
pascal@17989 147 - return -EINVAL;
pascal@17989 148 - }
pascal@17989 149 - s->offsets = g_malloc(offsets_size);
pascal@17990 150 + /* initialize zlib engine */
pascal@17990 151 + max_compressed_block_size = s->block_size + s->block_size/1000 + 12 + 4;
pascal@17990 152 + s->compressed_block = g_malloc(max_compressed_block_size + 1);
pascal@17990 153 + s->uncompressed_block = g_malloc(s->block_size);
pascal@17990 154
pascal@17990 155 - ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
pascal@17990 156 - if (ret < 0) {
pascal@17990 157 + if (inflateInit(&s->zstream) != Z_OK) {
pascal@17990 158 + ret = -EINVAL;
pascal@17990 159 goto fail;
pascal@17990 160 }
pascal@17990 161
pascal@17990 162 - for (i = 0; i < s->n_blocks + 1; i++) {
pascal@17990 163 - uint64_t size;
pascal@17990 164 + /* read offsets */
pascal@17266 165 + if (s->n_blocks + 1 == 0) {
pascal@17266 166 + cloop_tail tail;
pascal@17266 167 + int64_t end = bdrv_getlength(bs->file);
pascal@17266 168 + void *p;
pascal@17266 169 + uint32_t toclen, len;
pascal@17989 170
pascal@17990 171 - s->offsets[i] = be64_to_cpu(s->offsets[i]);
pascal@17990 172 - if (i == 0) {
pascal@17990 173 - continue;
pascal@17266 174 + ret = bdrv_pread(bs->file, end - sizeof(tail), &tail, sizeof(tail));
pascal@17266 175 + if (ret < 0) {
pascal@17266 176 + goto fail;
pascal@17990 177 }
pascal@17989 178
pascal@17990 179 - if (s->offsets[i] < s->offsets[i - 1]) {
pascal@17990 180 - error_setg(errp, "offsets not monotonically increasing at "
pascal@17990 181 - "index %u, image file is corrupt", i);
pascal@17990 182 - ret = -EINVAL;
pascal@17990 183 - goto fail;
pascal@17266 184 + s->n_blocks = be32_to_cpu(tail.num_blocks);
pascal@17266 185 + offsets_size = s->n_blocks * sizeof(block_info);
pascal@17989 186 + if (offsets_size > 512 * 1024 * 1024) {
pascal@17989 187 + /* Prevent ridiculous offsets_size which causes memory allocation to
pascal@17989 188 + * fail or overflows bdrv_pread() size. In practice the 512 MB
pascal@17989 189 + * offsets[] limit supports 16 TB images at 256 KB block size.
pascal@17989 190 + */
pascal@17989 191 + error_setg(errp, "image requires too many offsets, "
pascal@17989 192 + "try increasing block size");
pascal@17989 193 + return -EINVAL;
pascal@17989 194 }
pascal@17266 195 + len = be32_to_cpu(tail.table_size);
pascal@17266 196 + toclen = (be32_to_cpu(tail.index_size) & 255) * s->n_blocks;
pascal@17989 197
pascal@17990 198 - size = s->offsets[i] - s->offsets[i - 1];
pascal@17266 199 + s->offsets = g_malloc(offsets_size);
pascal@17266 200 + p = g_malloc(len);
pascal@17990 201
pascal@17990 202 - /* Compressed blocks should be smaller than the uncompressed block size
pascal@17990 203 - * but maybe compression performed poorly so the compressed block is
pascal@17990 204 - * actually bigger. Clamp down on unrealistic values to prevent
pascal@17990 205 - * ridiculous s->compressed_block allocation.
pascal@17990 206 - */
pascal@17990 207 - if (size > 2 * MAX_BLOCK_SIZE) {
pascal@17990 208 - error_setg(errp, "invalid compressed block size at index %u, "
pascal@17990 209 - "image file is corrupt", i);
pascal@17266 210 + ret = bdrv_pread(bs->file, end - sizeof(tail) - len, p, len);
pascal@17266 211 + if (ret < 0) {
pascal@17266 212 + goto fail;
pascal@17266 213 + }
pascal@17266 214 + s->zstream.next_in = p;
pascal@17266 215 + s->zstream.avail_in = len;
pascal@17266 216 + s->zstream.next_out = s->offsets;
pascal@17266 217 + s->zstream.avail_out = toclen;
pascal@17266 218 + ret = inflateReset(&s->zstream);
pascal@17266 219 + if (ret != Z_OK) {
pascal@17989 220 ret = -EINVAL;
pascal@17989 221 goto fail;
pascal@17989 222 }
pascal@17989 223 -
pascal@17990 224 - if (size > max_compressed_block_size) {
pascal@17990 225 - max_compressed_block_size = size;
pascal@17266 226 + ret = inflate(&s->zstream, Z_FINISH);
pascal@17266 227 + if (ret != Z_STREAM_END || s->zstream.total_out != toclen) {
pascal@17990 228 + ret = -EINVAL;
pascal@17990 229 + goto fail;
pascal@17989 230 }
pascal@17266 231 + g_free(p);
pascal@17990 232 }
pascal@17266 233 + else {
pascal@17266 234 + offsets_size = s->n_blocks * sizeof(block_info);
pascal@17989 235 + if (offsets_size > 512 * 1024 * 1024) {
pascal@17989 236 + /* Prevent ridiculous offsets_size which causes memory allocation to
pascal@17989 237 + * fail or overflows bdrv_pread() size. In practice the 512 MB
pascal@17989 238 + * offsets[] limit supports 16 TB images at 256 KB block size.
pascal@17989 239 + */
pascal@17989 240 + error_setg(errp, "image requires too many offsets, "
pascal@17989 241 + "try increasing block size");
pascal@17989 242 + return -EINVAL;
pascal@17989 243 + }
pascal@17266 244 + s->offsets = g_malloc(offsets_size);
pascal@17266 245
pascal@17266 246 - /* initialize zlib engine */
pascal@17266 247 - s->compressed_block = g_malloc(max_compressed_block_size + 1);
pascal@17266 248 - s->uncompressed_block = g_malloc(s->block_size);
pascal@17266 249 - if (inflateInit(&s->zstream) != Z_OK) {
pascal@17990 250 + ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
pascal@17990 251 + if (ret < 0) {
pascal@17990 252 + goto fail;
pascal@17990 253 + }
pascal@17990 254 + }
pascal@17989 255 + ret = build_index(s->offsets, s->n_blocks);
pascal@17989 256 + if (ret) {
pascal@17989 257 + error_setg(errp, "invalid compressed block size at index %u, "
pascal@17989 258 + "image file is corrupt", ret-1);
pascal@17989 259 ret = -EINVAL;
pascal@17989 260 goto fail;
pascal@17266 261 }
pascal@17266 262 +
pascal@17266 263 s->current_block = s->n_blocks;
pascal@17266 264
pascal@17266 265 s->sectors_per_block = s->block_size/512;
pascal@17990 266 @@ -184,10 +280,10 @@
pascal@17266 267
pascal@17266 268 if (s->current_block != block_num) {
pascal@17266 269 int ret;
pascal@17266 270 - uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
pascal@17266 271 + uint32_t bytes = s->offsets[block_num].size;
pascal@17266 272
pascal@17266 273 - ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
pascal@17266 274 - bytes);
pascal@17266 275 + ret = bdrv_pread(bs->file, s->offsets[block_num].offset,
pascal@17266 276 + s->compressed_block, bytes);
pascal@17266 277 if (ret != bytes) {
pascal@17266 278 return -1;
pascal@17266 279 }