wok-next annotate qemu/stuff/patches/cloop.u @ rev 20661

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