dmg.c 21.4 KB
Newer Older
1 2
/*
 * QEMU Block driver for DMG images
3
 *
4
 * Copyright (c) 2004 Johannes E. Schindelin
5
 *
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
P
Peter Maydell 已提交
24
#include "qemu/osdep.h"
25
#include "qapi/error.h"
P
pbrook 已提交
26
#include "qemu-common.h"
27
#include "block/block_int.h"
28
#include "qemu/bswap.h"
29
#include "qemu/error-report.h"
30
#include "qemu/module.h"
F
Fam Zheng 已提交
31 32 33 34
#include "dmg.h"

int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
                          char *next_out, unsigned int avail_out);
35

36 37 38 39 40 41 42 43
enum {
    /* Limit chunk sizes to prevent unreasonable amounts of memory being used
     * or truncating when converting to 32-bit types
     */
    DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */
    DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
};

44 45
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
{
46 47 48 49 50 51 52 53 54 55
    int len;

    if (!filename) {
        return 0;
    }

    len = strlen(filename);
    if (len > 4 && !strcmp(filename + len - 4, ".dmg")) {
        return 2;
    }
56 57 58
    return 0;
}

K
Kevin Wolf 已提交
59
static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
60
{
K
Kevin Wolf 已提交
61 62 63
    uint64_t buffer;
    int ret;

64
    ret = bdrv_pread(bs->file, offset, &buffer, 8);
K
Kevin Wolf 已提交
65 66 67 68 69 70
    if (ret < 0) {
        return ret;
    }

    *result = be64_to_cpu(buffer);
    return 0;
71 72
}

K
Kevin Wolf 已提交
73
static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
74
{
K
Kevin Wolf 已提交
75 76 77
    uint32_t buffer;
    int ret;

78
    ret = bdrv_pread(bs->file, offset, &buffer, 4);
K
Kevin Wolf 已提交
79 80 81 82 83 84
    if (ret < 0) {
        return ret;
    }

    *result = be32_to_cpu(buffer);
    return 0;
85 86
}

87 88 89 90 91 92 93 94 95 96
static inline uint64_t buff_read_uint64(const uint8_t *buffer, int64_t offset)
{
    return be64_to_cpu(*(uint64_t *)&buffer[offset]);
}

static inline uint32_t buff_read_uint32(const uint8_t *buffer, int64_t offset)
{
    return be32_to_cpu(*(uint32_t *)&buffer[offset]);
}

97 98 99 100 101 102 103 104 105 106 107 108
/* Increase max chunk sizes, if necessary.  This function is used to calculate
 * the buffer sizes needed for compressed/uncompressed chunk I/O.
 */
static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
                                  uint32_t *max_compressed_size,
                                  uint32_t *max_sectors_per_chunk)
{
    uint32_t compressed_size = 0;
    uint32_t uncompressed_sectors = 0;

    switch (s->types[chunk]) {
    case 0x80000005: /* zlib compressed */
109
    case 0x80000006: /* bzip2 compressed */
110 111 112 113 114 115 116
        compressed_size = s->lengths[chunk];
        uncompressed_sectors = s->sectorcounts[chunk];
        break;
    case 1: /* copy */
        uncompressed_sectors = (s->lengths[chunk] + 511) / 512;
        break;
    case 2: /* zero */
P
Peter Wu 已提交
117 118 119
        /* as the all-zeroes block may be large, it is treated specially: the
         * sector is not copied from a large buffer, a simple memset is used
         * instead. Therefore uncompressed_sectors does not need to be set. */
120 121 122 123 124 125 126 127 128 129 130
        break;
    }

    if (compressed_size > *max_compressed_size) {
        *max_compressed_size = compressed_size;
    }
    if (uncompressed_sectors > *max_sectors_per_chunk) {
        *max_sectors_per_chunk = uncompressed_sectors;
    }
}

131
static int64_t dmg_find_koly_offset(BdrvChild *file, Error **errp)
132
{
133
    BlockDriverState *file_bs = file->bs;
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
    int64_t length;
    int64_t offset = 0;
    uint8_t buffer[515];
    int i, ret;

    /* bdrv_getlength returns a multiple of block size (512), rounded up. Since
     * dmg images can have odd sizes, try to look for the "koly" magic which
     * marks the begin of the UDIF trailer (512 bytes). This magic can be found
     * in the last 511 bytes of the second-last sector or the first 4 bytes of
     * the last sector (search space: 515 bytes) */
    length = bdrv_getlength(file_bs);
    if (length < 0) {
        error_setg_errno(errp, -length,
            "Failed to get file size while reading UDIF trailer");
        return length;
    } else if (length < 512) {
        error_setg(errp, "dmg file must be at least 512 bytes long");
        return -EINVAL;
    }
    if (length > 511 + 512) {
        offset = length - 511 - 512;
    }
    length = length < 515 ? length : 515;
157
    ret = bdrv_pread(file, offset, buffer, length);
158 159 160 161 162 163 164 165 166 167 168 169 170 171
    if (ret < 0) {
        error_setg_errno(errp, -ret, "Failed while reading UDIF trailer");
        return ret;
    }
    for (i = 0; i < length - 3; i++) {
        if (buffer[i] == 'k' && buffer[i+1] == 'o' &&
            buffer[i+2] == 'l' && buffer[i+3] == 'y') {
            return offset + i;
        }
    }
    error_setg(errp, "Could not locate UDIF trailer in dmg file");
    return -EINVAL;
}

172 173 174 175
/* used when building the sector table */
typedef struct DmgHeaderState {
    /* used internally by dmg_read_mish_block to remember offsets of blocks
     * across calls */
176
    uint64_t data_fork_offset;
177 178 179 180 181
    /* exported for dmg_open */
    uint32_t max_compressed_size;
    uint32_t max_sectors_per_chunk;
} DmgHeaderState;

182 183 184 185 186 187 188
static bool dmg_is_known_block_type(uint32_t entry_type)
{
    switch (entry_type) {
    case 0x00000001:    /* uncompressed */
    case 0x00000002:    /* zeroes */
    case 0x80000005:    /* zlib */
        return true;
F
Fam Zheng 已提交
189 190
    case 0x80000006:    /* bzip2 */
        return !!dmg_uncompress_bz2;
191 192 193 194 195
    default:
        return false;
    }
}

196 197
static int dmg_read_mish_block(BDRVDMGState *s, DmgHeaderState *ds,
                               uint8_t *buffer, uint32_t count)
198 199 200 201 202
{
    uint32_t type, i;
    int ret;
    size_t new_size;
    uint32_t chunk_count;
203
    int64_t offset = 0;
204 205
    uint64_t data_offset;
    uint64_t in_offset = ds->data_fork_offset;
206
    uint64_t out_offset;
207

208
    type = buff_read_uint32(buffer, offset);
209 210 211 212 213 214
    /* skip data that is not a valid MISH block (invalid magic or too small) */
    if (type != 0x6d697368 || count < 244) {
        /* assume success for now */
        return 0;
    }

215 216 217
    /* chunk offsets are relative to this sector number */
    out_offset = buff_read_uint64(buffer, offset + 8);

218 219 220 221 222 223
    /* location in data fork for (compressed) blob (in bytes) */
    data_offset = buff_read_uint64(buffer, offset + 0x18);
    in_offset += data_offset;

    /* move to begin of chunk entries */
    offset += 204;
224 225 226 227 228 229 230 231 232 233

    chunk_count = (count - 204) / 40;
    new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
    s->types = g_realloc(s->types, new_size / 2);
    s->offsets = g_realloc(s->offsets, new_size);
    s->lengths = g_realloc(s->lengths, new_size);
    s->sectors = g_realloc(s->sectors, new_size);
    s->sectorcounts = g_realloc(s->sectorcounts, new_size);

    for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
234
        s->types[i] = buff_read_uint32(buffer, offset);
235
        if (!dmg_is_known_block_type(s->types[i])) {
236 237
            chunk_count--;
            i--;
238
            offset += 40;
239 240 241
            continue;
        }

242 243
        /* sector number */
        s->sectors[i] = buff_read_uint64(buffer, offset + 8);
244
        s->sectors[i] += out_offset;
245

246 247
        /* sector count */
        s->sectorcounts[i] = buff_read_uint64(buffer, offset + 0x10);
248

P
Peter Wu 已提交
249 250 251
        /* all-zeroes sector (type 2) does not need to be "uncompressed" and can
         * therefore be unbounded. */
        if (s->types[i] != 2 && s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
252 253 254 255 256 257 258
            error_report("sector count %" PRIu64 " for chunk %" PRIu32
                         " is larger than max (%u)",
                         s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
            ret = -EINVAL;
            goto fail;
        }

259 260
        /* offset in (compressed) data fork */
        s->offsets[i] = buff_read_uint64(buffer, offset + 0x18);
261
        s->offsets[i] += in_offset;
262

263 264
        /* length in (compressed) data fork */
        s->lengths[i] = buff_read_uint64(buffer, offset + 0x20);
265 266 267 268 269 270 271 272 273 274 275

        if (s->lengths[i] > DMG_LENGTHS_MAX) {
            error_report("length %" PRIu64 " for chunk %" PRIu32
                         " is larger than max (%u)",
                         s->lengths[i], i, DMG_LENGTHS_MAX);
            ret = -EINVAL;
            goto fail;
        }

        update_max_chunk_size(s, i, &ds->max_compressed_size,
                              &ds->max_sectors_per_chunk);
276
        offset += 40;
277 278 279 280 281 282 283 284
    }
    s->n_chunks += chunk_count;
    return 0;

fail:
    return ret;
}

285 286
static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
                                  uint64_t info_begin, uint64_t info_length)
287
{
288
    BDRVDMGState *s = bs->opaque;
K
Kevin Wolf 已提交
289
    int ret;
290
    uint32_t count, rsrc_data_offset;
291
    uint8_t *buffer = NULL;
292 293
    uint64_t info_end;
    uint64_t offset;
294

295
    /* read offset from begin of resource fork (info_begin) to resource data */
296
    ret = read_uint32(bs, info_begin, &rsrc_data_offset);
K
Kevin Wolf 已提交
297 298
    if (ret < 0) {
        goto fail;
299
    } else if (rsrc_data_offset > info_length) {
K
Kevin Wolf 已提交
300
        ret = -EINVAL;
C
Christoph Hellwig 已提交
301 302 303
        goto fail;
    }

304 305
    /* read length of resource data */
    ret = read_uint32(bs, info_begin + 8, &count);
K
Kevin Wolf 已提交
306 307
    if (ret < 0) {
        goto fail;
308
    } else if (count == 0 || rsrc_data_offset + count > info_length) {
K
Kevin Wolf 已提交
309
        ret = -EINVAL;
C
Christoph Hellwig 已提交
310 311 312
        goto fail;
    }

313
    /* begin of resource data (consisting of one or more resources) */
314 315 316 317 318
    offset = info_begin + rsrc_data_offset;

    /* end of resource data (there is possibly a following resource map
     * which will be ignored). */
    info_end = offset + count;
319

320
    /* read offsets (mish blocks) from one or more resources in resource data */
C
Christoph Hellwig 已提交
321
    while (offset < info_end) {
322
        /* size of following resource */
K
Kevin Wolf 已提交
323 324 325
        ret = read_uint32(bs, offset, &count);
        if (ret < 0) {
            goto fail;
326
        } else if (count == 0 || count > info_end - offset) {
K
Kevin Wolf 已提交
327 328 329
            ret = -EINVAL;
            goto fail;
        }
C
Christoph Hellwig 已提交
330 331
        offset += 4;

332
        buffer = g_realloc(buffer, count);
333
        ret = bdrv_pread(bs->file, offset, buffer, count);
334 335 336 337 338
        if (ret < 0) {
            goto fail;
        }

        ret = dmg_read_mish_block(s, ds, buffer, count);
K
Kevin Wolf 已提交
339 340 341
        if (ret < 0) {
            goto fail;
        }
342 343
        /* advance offset by size of resource */
        offset += count;
344
    }
345
    ret = 0;
346 347

fail:
348
    g_free(buffer);
349 350 351
    return ret;
}

P
Peter Wu 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds,
                              uint64_t info_begin, uint64_t info_length)
{
    BDRVDMGState *s = bs->opaque;
    int ret;
    uint8_t *buffer = NULL;
    char *data_begin, *data_end;

    /* Have at least some length to avoid NULL for g_malloc. Attempt to set a
     * safe upper cap on the data length. A test sample had a XML length of
     * about 1 MiB. */
    if (info_length == 0 || info_length > 16 * 1024 * 1024) {
        ret = -EINVAL;
        goto fail;
    }

    buffer = g_malloc(info_length + 1);
    buffer[info_length] = '\0';
370
    ret = bdrv_pread(bs->file, info_begin, buffer, info_length);
P
Peter Wu 已提交
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
    if (ret != info_length) {
        ret = -EINVAL;
        goto fail;
    }

    /* look for <data>...</data>. The data is 284 (0x11c) bytes after base64
     * decode. The actual data element has 431 (0x1af) bytes which includes tabs
     * and line feeds. */
    data_end = (char *)buffer;
    while ((data_begin = strstr(data_end, "<data>")) != NULL) {
        guchar *mish;
        gsize out_len = 0;

        data_begin += 6;
        data_end = strstr(data_begin, "</data>");
        /* malformed XML? */
        if (data_end == NULL) {
            ret = -EINVAL;
            goto fail;
        }
        *data_end++ = '\0';
        mish = g_base64_decode(data_begin, &out_len);
        ret = dmg_read_mish_block(s, ds, mish, (uint32_t)out_len);
        g_free(mish);
        if (ret < 0) {
            goto fail;
        }
    }
    ret = 0;

fail:
    g_free(buffer);
    return ret;
}

406 407 408 409 410 411
static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
                    Error **errp)
{
    BDRVDMGState *s = bs->opaque;
    DmgHeaderState ds;
    uint64_t rsrc_fork_offset, rsrc_fork_length;
P
Peter Wu 已提交
412
    uint64_t plist_xml_offset, plist_xml_length;
413 414 415
    int64_t offset;
    int ret;

416 417 418 419 420 421
    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
                               false, errp);
    if (!bs->file) {
        return -EINVAL;
    }

F
Fam Zheng 已提交
422
    block_module_load_one("dmg-bz2");
423
    bs->read_only = true;
424

425 426 427
    s->n_chunks = 0;
    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
    /* used by dmg_read_mish_block to keep track of the current I/O position */
428
    ds.data_fork_offset = 0;
429 430 431 432
    ds.max_compressed_size = 1;
    ds.max_sectors_per_chunk = 1;

    /* locate the UDIF trailer */
433
    offset = dmg_find_koly_offset(bs->file, errp);
434 435 436 437 438
    if (offset < 0) {
        ret = offset;
        goto fail;
    }

439 440 441 442 443 444 445 446 447
    /* offset of data fork (DataForkOffset) */
    ret = read_uint64(bs, offset + 0x18, &ds.data_fork_offset);
    if (ret < 0) {
        goto fail;
    } else if (ds.data_fork_offset > offset) {
        ret = -EINVAL;
        goto fail;
    }

448 449 450 451 452 453 454 455 456
    /* offset of resource fork (RsrcForkOffset) */
    ret = read_uint64(bs, offset + 0x28, &rsrc_fork_offset);
    if (ret < 0) {
        goto fail;
    }
    ret = read_uint64(bs, offset + 0x30, &rsrc_fork_length);
    if (ret < 0) {
        goto fail;
    }
457 458 459 460 461
    if (rsrc_fork_offset >= offset ||
        rsrc_fork_length > offset - rsrc_fork_offset) {
        ret = -EINVAL;
        goto fail;
    }
P
Peter Wu 已提交
462 463 464 465 466 467 468 469 470 471 472 473 474 475
    /* offset of property list (XMLOffset) */
    ret = read_uint64(bs, offset + 0xd8, &plist_xml_offset);
    if (ret < 0) {
        goto fail;
    }
    ret = read_uint64(bs, offset + 0xe0, &plist_xml_length);
    if (ret < 0) {
        goto fail;
    }
    if (plist_xml_offset >= offset ||
        plist_xml_length > offset - plist_xml_offset) {
        ret = -EINVAL;
        goto fail;
    }
476 477 478 479 480 481 482 483
    ret = read_uint64(bs, offset + 0x1ec, (uint64_t *)&bs->total_sectors);
    if (ret < 0) {
        goto fail;
    }
    if (bs->total_sectors < 0) {
        ret = -EINVAL;
        goto fail;
    }
484 485 486 487 488 489
    if (rsrc_fork_length != 0) {
        ret = dmg_read_resource_fork(bs, &ds,
                                     rsrc_fork_offset, rsrc_fork_length);
        if (ret < 0) {
            goto fail;
        }
P
Peter Wu 已提交
490 491 492 493 494
    } else if (plist_xml_length != 0) {
        ret = dmg_read_plist_xml(bs, &ds, plist_xml_offset, plist_xml_length);
        if (ret < 0) {
            goto fail;
        }
495 496 497 498
    } else {
        ret = -EINVAL;
        goto fail;
    }
499 500

    /* initialize zlib engine */
K
Kevin Wolf 已提交
501
    s->compressed_chunk = qemu_try_blockalign(bs->file->bs,
502
                                              ds.max_compressed_size + 1);
K
Kevin Wolf 已提交
503
    s->uncompressed_chunk = qemu_try_blockalign(bs->file->bs,
504
                                                512 * ds.max_sectors_per_chunk);
505 506 507 508 509
    if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) {
        ret = -ENOMEM;
        goto fail;
    }

510
    if (inflateInit(&s->zstream) != Z_OK) {
K
Kevin Wolf 已提交
511 512 513
        ret = -EINVAL;
        goto fail;
    }
514 515

    s->current_chunk = s->n_chunks;
516

517
    qemu_co_mutex_init(&s->lock);
518
    return 0;
K
Kevin Wolf 已提交
519

C
Christoph Hellwig 已提交
520
fail:
K
Kevin Wolf 已提交
521 522 523 524 525
    g_free(s->types);
    g_free(s->offsets);
    g_free(s->lengths);
    g_free(s->sectors);
    g_free(s->sectorcounts);
526 527
    qemu_vfree(s->compressed_chunk);
    qemu_vfree(s->uncompressed_chunk);
K
Kevin Wolf 已提交
528
    return ret;
529 530
}

531 532
static void dmg_refresh_limits(BlockDriverState *bs, Error **errp)
{
533
    bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
534 535
}

536
static inline int is_sector_in_chunk(BDRVDMGState* s,
537
                uint32_t chunk_num, uint64_t sector_num)
538
{
539 540 541 542 543 544
    if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num ||
            s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) {
        return 0;
    } else {
        return -1;
    }
545 546
}

547
static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num)
548 549
{
    /* binary search */
550 551 552 553 554 555 556 557 558 559
    uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3;
    while (chunk1 != chunk2) {
        chunk3 = (chunk1 + chunk2) / 2;
        if (s->sectors[chunk3] > sector_num) {
            chunk2 = chunk3;
        } else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) {
            return chunk3;
        } else {
            chunk1 = chunk3;
        }
560 561 562 563
    }
    return s->n_chunks; /* error */
}

564
static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
565
{
C
Christoph Hellwig 已提交
566 567
    BDRVDMGState *s = bs->opaque;

568 569 570
    if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) {
        int ret;
        uint32_t chunk = search_chunk(s, sector_num);
571

572 573 574
        if (chunk >= s->n_chunks) {
            return -1;
        }
575

576
        s->current_chunk = s->n_chunks;
577
        switch (s->types[chunk]) { /* block entry type */
578 579 580
        case 0x80000005: { /* zlib compressed */
            /* we need to buffer, because only the chunk as whole can be
             * inflated. */
581
            ret = bdrv_pread(bs->file, s->offsets[chunk],
582
                             s->compressed_chunk, s->lengths[chunk]);
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
            if (ret != s->lengths[chunk]) {
                return -1;
            }

            s->zstream.next_in = s->compressed_chunk;
            s->zstream.avail_in = s->lengths[chunk];
            s->zstream.next_out = s->uncompressed_chunk;
            s->zstream.avail_out = 512 * s->sectorcounts[chunk];
            ret = inflateReset(&s->zstream);
            if (ret != Z_OK) {
                return -1;
            }
            ret = inflate(&s->zstream, Z_FINISH);
            if (ret != Z_STREAM_END ||
                s->zstream.total_out != 512 * s->sectorcounts[chunk]) {
                return -1;
            }
            break; }
601
        case 0x80000006: /* bzip2 compressed */
F
Fam Zheng 已提交
602 603 604
            if (!dmg_uncompress_bz2) {
                break;
            }
605 606
            /* we need to buffer, because only the chunk as whole can be
             * inflated. */
607
            ret = bdrv_pread(bs->file, s->offsets[chunk],
608 609 610 611 612
                             s->compressed_chunk, s->lengths[chunk]);
            if (ret != s->lengths[chunk]) {
                return -1;
            }

F
Fam Zheng 已提交
613 614 615 616 617 618 619
            ret = dmg_uncompress_bz2((char *)s->compressed_chunk,
                                     (unsigned int) s->lengths[chunk],
                                     (char *)s->uncompressed_chunk,
                                     (unsigned int)
                                         (512 * s->sectorcounts[chunk]));
            if (ret < 0) {
                return ret;
620 621
            }
            break;
622
        case 1: /* copy */
623
            ret = bdrv_pread(bs->file, s->offsets[chunk],
C
Christoph Hellwig 已提交
624
                             s->uncompressed_chunk, s->lengths[chunk]);
625 626 627 628 629
            if (ret != s->lengths[chunk]) {
                return -1;
            }
            break;
        case 2: /* zero */
P
Peter Wu 已提交
630 631
            /* see dmg_read, it is treated specially. No buffer needs to be
             * pre-filled, the zeroes can be set directly. */
632 633 634
            break;
        }
        s->current_chunk = chunk;
635 636 637 638
    }
    return 0;
}

639 640 641
static int coroutine_fn
dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
              QEMUIOVector *qiov, int flags)
642 643
{
    BDRVDMGState *s = bs->opaque;
644 645 646 647 648 649 650 651
    uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
    int nb_sectors = bytes >> BDRV_SECTOR_BITS;
    int ret, i;

    assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
    assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);

    qemu_co_mutex_lock(&s->lock);
652

653 654
    for (i = 0; i < nb_sectors; i++) {
        uint32_t sector_offset_in_chunk;
655 656
        void *data;

657
        if (dmg_read_chunk(bs, sector_num + i) != 0) {
658 659
            ret = -EIO;
            goto fail;
660
        }
P
Peter Wu 已提交
661 662 663 664
        /* Special case: current chunk is all zeroes. Do not perform a memcpy as
         * s->uncompressed_chunk may be too small to cover the large all-zeroes
         * section. dmg_read_chunk is called to find s->current_chunk */
        if (s->types[s->current_chunk] == 2) { /* all zeroes block entry */
665
            qemu_iovec_memset(qiov, i * 512, 0, 512);
P
Peter Wu 已提交
666 667
            continue;
        }
668
        sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk];
669 670
        data = s->uncompressed_chunk + sector_offset_in_chunk * 512;
        qemu_iovec_from_buf(qiov, i * 512, data, 512);
671 672
    }

673 674
    ret = 0;
fail:
675 676 677 678
    qemu_co_mutex_unlock(&s->lock);
    return ret;
}

679 680 681
static void dmg_close(BlockDriverState *bs)
{
    BDRVDMGState *s = bs->opaque;
K
Kevin Wolf 已提交
682 683 684 685 686 687

    g_free(s->types);
    g_free(s->offsets);
    g_free(s->lengths);
    g_free(s->sectors);
    g_free(s->sectorcounts);
688 689
    qemu_vfree(s->compressed_chunk);
    qemu_vfree(s->uncompressed_chunk);
K
Kevin Wolf 已提交
690

691 692 693
    inflateEnd(&s->zstream);
}

694
static BlockDriver bdrv_dmg = {
695 696 697 698
    .format_name    = "dmg",
    .instance_size  = sizeof(BDRVDMGState),
    .bdrv_probe     = dmg_probe,
    .bdrv_open      = dmg_open,
699
    .bdrv_refresh_limits = dmg_refresh_limits,
700
    .bdrv_child_perm     = bdrv_format_default_perms,
701
    .bdrv_co_preadv = dmg_co_preadv,
702
    .bdrv_close     = dmg_close,
703
};
704 705 706 707 708 709 710

static void bdrv_dmg_init(void)
{
    bdrv_register(&bdrv_dmg);
}

block_init(bdrv_dmg_init);