static int dmg_open(BlockDriverState *bs, QDict *options, int flags,

                    Error **errp)

{

    BDRVDMGState *s = bs->opaque;

    uint64_t info_begin, info_end, last_in_offset, last_out_offset;

    uint32_t count, tmp;

    uint32_t max_compressed_size = 1, max_sectors_per_chunk = 1, i;

    int64_t offset;

    int ret;



    bs->read_only = 1;

    s->n_chunks = 0;

    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;



    /* read offset of info blocks */

    offset = bdrv_getlength(bs->file);

    if (offset < 0) {

        ret = offset;

        goto fail;

    }

    offset -= 0x1d8;



    ret = read_uint64(bs, offset, &info_begin);

    if (ret < 0) {

        goto fail;

    } else if (info_begin == 0) {

        ret = -EINVAL;

        goto fail;

    }



    ret = read_uint32(bs, info_begin, &tmp);

    if (ret < 0) {

        goto fail;

    } else if (tmp != 0x100) {

        ret = -EINVAL;

        goto fail;

    }



    ret = read_uint32(bs, info_begin + 4, &count);

    if (ret < 0) {

        goto fail;

    } else if (count == 0) {

        ret = -EINVAL;

        goto fail;

    }

    info_end = info_begin + count;



    offset = info_begin + 0x100;



    /* read offsets */

    last_in_offset = last_out_offset = 0;

    while (offset < info_end) {

        uint32_t type;



        ret = read_uint32(bs, offset, &count);

        if (ret < 0) {

            goto fail;

        } else if (count == 0) {

            ret = -EINVAL;

            goto fail;

        }

        offset += 4;



        ret = read_uint32(bs, offset, &type);

        if (ret < 0) {

            goto fail;

        }



        if (type == 0x6d697368 && count >= 244) {

            size_t new_size;

            uint32_t chunk_count;



            offset += 4;

            offset += 200;



            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++) {

                ret = read_uint32(bs, offset, &s->types[i]);

                if (ret < 0) {

                    goto fail;

                }

                offset += 4;

                if (s->types[i] != 0x80000005 && s->types[i] != 1 &&

                    s->types[i] != 2) {

                    if (s->types[i] == 0xffffffff && i > 0) {

                        last_in_offset = s->offsets[i - 1] + s->lengths[i - 1];

                        last_out_offset = s->sectors[i - 1] +

                                          s->sectorcounts[i - 1];

                    }

                    chunk_count--;

                    i--;

                    offset += 36;

                    continue;

                }

                offset += 4;



                ret = read_uint64(bs, offset, &s->sectors[i]);

                if (ret < 0) {

                    goto fail;

                }

                s->sectors[i] += last_out_offset;

                offset += 8;



                ret = read_uint64(bs, offset, &s->sectorcounts[i]);

                if (ret < 0) {

                    goto fail;

                }

                offset += 8;



                if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {

                    error_report("sector count %" PRIu64 " for chunk %" PRIu32

                                 " is larger than max (%u)",

                                 s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);

                    ret = -EINVAL;

                    goto fail;

                }



                ret = read_uint64(bs, offset, &s->offsets[i]);

                if (ret < 0) {

                    goto fail;

                }

                s->offsets[i] += last_in_offset;

                offset += 8;



                ret = read_uint64(bs, offset, &s->lengths[i]);

                if (ret < 0) {

                    goto fail;

                }

                offset += 8;



                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, &max_compressed_size,

                                      &max_sectors_per_chunk);

            }

            s->n_chunks += chunk_count;

        }

    }



    /* initialize zlib engine */

    s->compressed_chunk = qemu_try_blockalign(bs->file,

                                              max_compressed_size + 1);

    s->uncompressed_chunk = qemu_try_blockalign(bs->file,

                                                512 * max_sectors_per_chunk);

    if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) {

        ret = -ENOMEM;

        goto fail;

    }



    if (inflateInit(&s->zstream) != Z_OK) {

        ret = -EINVAL;

        goto fail;

    }



    s->current_chunk = s->n_chunks;



    qemu_co_mutex_init(&s->lock);

    return 0;



fail:

    g_free(s->types);

    g_free(s->offsets);

    g_free(s->lengths);

    g_free(s->sectors);

    g_free(s->sectorcounts);

    qemu_vfree(s->compressed_chunk);

    qemu_vfree(s->uncompressed_chunk);

    return ret;

}

static int dmg_open(BlockDriverState *bs, QDict *options, int flags,

                    Error **errp)

{

    BDRVDMGState *s = bs->opaque;

    uint64_t info_begin, info_end, last_in_offset, last_out_offset;

    uint32_t count, tmp;

    uint32_t max_compressed_size = 1, max_sectors_per_chunk = 1, i;

    int64_t offset;

    int ret;



    bs->read_only = 1;

    s->n_chunks = 0;

    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;



    

    offset = bdrv_getlength(bs->file);

    if (offset < 0) {

        ret = offset;

        goto fail;

    }

    offset -= 0x1d8;



    ret = read_uint64(bs, offset, &info_begin);

    if (ret < 0) {

        goto fail;

    } else if (info_begin == 0) {

        ret = -EINVAL;

        goto fail;

    }



    ret = read_uint32(bs, info_begin, &tmp);

    if (ret < 0) {

        goto fail;

    } else if (tmp != 0x100) {

        ret = -EINVAL;

        goto fail;

    }



    ret = read_uint32(bs, info_begin + 4, &count);

    if (ret < 0) {

        goto fail;

    } else if (count == 0) {

        ret = -EINVAL;

        goto fail;

    }

    info_end = info_begin + count;



    offset = info_begin + 0x100;



    

    last_in_offset = last_out_offset = 0;

    while (offset < info_end) {

        uint32_t type;



        ret = read_uint32(bs, offset, &count);

        if (ret < 0) {

            goto fail;

        } else if (count == 0) {

            ret = -EINVAL;

            goto fail;

        }

        offset += 4;



        ret = read_uint32(bs, offset, &type);

        if (ret < 0) {

            goto fail;

        }



        if (type == 0x6d697368 && count >= 244) {

            size_t new_size;

            uint32_t chunk_count;



            offset += 4;

            offset += 200;



            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++) {

                ret = read_uint32(bs, offset, &s->types[i]);

                if (ret < 0) {

                    goto fail;

                }

                offset += 4;

                if (s->types[i] != 0x80000005 && s->types[i] != 1 &&

                    s->types[i] != 2) {

                    if (s->types[i] == 0xffffffff && i > 0) {

                        last_in_offset = s->offsets[i - 1] + s->lengths[i - 1];

                        last_out_offset = s->sectors[i - 1] +

                                          s->sectorcounts[i - 1];

                    }

                    chunk_count--;

                    i--;

                    offset += 36;

                    continue;

                }

                offset += 4;



                ret = read_uint64(bs, offset, &s->sectors[i]);

                if (ret < 0) {

                    goto fail;

                }

                s->sectors[i] += last_out_offset;

                offset += 8;



                ret = read_uint64(bs, offset, &s->sectorcounts[i]);

                if (ret < 0) {

                    goto fail;

                }

                offset += 8;



                if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {

                    error_report("sector count %" PRIu64 " for chunk %" PRIu32

                                 " is larger than max (%u)",

                                 s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);

                    ret = -EINVAL;

                    goto fail;

                }



                ret = read_uint64(bs, offset, &s->offsets[i]);

                if (ret < 0) {

                    goto fail;

                }

                s->offsets[i] += last_in_offset;

                offset += 8;



                ret = read_uint64(bs, offset, &s->lengths[i]);

                if (ret < 0) {

                    goto fail;

                }

                offset += 8;



                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, &max_compressed_size,

                                      &max_sectors_per_chunk);

            }

            s->n_chunks += chunk_count;

        }

    }



    

    s->compressed_chunk = qemu_try_blockalign(bs->file,

                                              max_compressed_size + 1);

    s->uncompressed_chunk = qemu_try_blockalign(bs->file,

                                                512 * max_sectors_per_chunk);

    if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) {

        ret = -ENOMEM;

        goto fail;

    }



    if (inflateInit(&s->zstream) != Z_OK) {

        ret = -EINVAL;

        goto fail;

    }



    s->current_chunk = s->n_chunks;



    qemu_co_mutex_init(&s->lock);

    return 0;



fail:

    g_free(s->types);

    g_free(s->offsets);

    g_free(s->lengths);

    g_free(s->sectors);

    g_free(s->sectorcounts);

    qemu_vfree(s->compressed_chunk);

    qemu_vfree(s->uncompressed_chunk);

    return ret;

}

    offset = bdrv_getlength(bs->file);     offset -= 0x1d8;     ret = read_uint64(bs, offset, &info_begin);
static int FUNC_0(BlockDriverState *VAR_0, QDict *VAR_1, int VAR_2,

                    Error **VAR_3)

{

    BDRVDMGState *s = VAR_0->opaque;

    uint64_t info_begin, info_end, last_in_offset, last_out_offset;

    uint32_t count, tmp;

    uint32_t max_compressed_size = 1, max_sectors_per_chunk = 1, i;

    int64_t offset;

    int VAR_4;



    VAR_0->read_only = 1;

    s->n_chunks = 0;

    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;



    

    offset = bdrv_getlength(VAR_0->file);

    if (offset < 0) {

        VAR_4 = offset;

        goto fail;

    }

    offset -= 0x1d8;



    VAR_4 = read_uint64(VAR_0, offset, &info_begin);

    if (VAR_4 < 0) {

        goto fail;

    } else if (info_begin == 0) {

        VAR_4 = -EINVAL;

        goto fail;

    }



    VAR_4 = read_uint32(VAR_0, info_begin, &tmp);

    if (VAR_4 < 0) {

        goto fail;

    } else if (tmp != 0x100) {

        VAR_4 = -EINVAL;

        goto fail;

    }



    VAR_4 = read_uint32(VAR_0, info_begin + 4, &count);

    if (VAR_4 < 0) {

        goto fail;

    } else if (count == 0) {

        VAR_4 = -EINVAL;

        goto fail;

    }

    info_end = info_begin + count;



    offset = info_begin + 0x100;



    

    last_in_offset = last_out_offset = 0;

    while (offset < info_end) {

        uint32_t type;



        VAR_4 = read_uint32(VAR_0, offset, &count);

        if (VAR_4 < 0) {

            goto fail;

        } else if (count == 0) {

            VAR_4 = -EINVAL;

            goto fail;

        }

        offset += 4;



        VAR_4 = read_uint32(VAR_0, offset, &type);

        if (VAR_4 < 0) {

            goto fail;

        }



        if (type == 0x6d697368 && count >= 244) {

            size_t new_size;

            uint32_t chunk_count;



            offset += 4;

            offset += 200;



            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++) {

                VAR_4 = read_uint32(VAR_0, offset, &s->types[i]);

                if (VAR_4 < 0) {

                    goto fail;

                }

                offset += 4;

                if (s->types[i] != 0x80000005 && s->types[i] != 1 &&

                    s->types[i] != 2) {

                    if (s->types[i] == 0xffffffff && i > 0) {

                        last_in_offset = s->offsets[i - 1] + s->lengths[i - 1];

                        last_out_offset = s->sectors[i - 1] +

                                          s->sectorcounts[i - 1];

                    }

                    chunk_count--;

                    i--;

                    offset += 36;

                    continue;

                }

                offset += 4;



                VAR_4 = read_uint64(VAR_0, offset, &s->sectors[i]);

                if (VAR_4 < 0) {

                    goto fail;

                }

                s->sectors[i] += last_out_offset;

                offset += 8;



                VAR_4 = read_uint64(VAR_0, offset, &s->sectorcounts[i]);

                if (VAR_4 < 0) {

                    goto fail;

                }

                offset += 8;



                if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {

                    error_report("sector count %" PRIu64 " for chunk %" PRIu32

                                 " is larger than max (%u)",

                                 s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);

                    VAR_4 = -EINVAL;

                    goto fail;

                }



                VAR_4 = read_uint64(VAR_0, offset, &s->offsets[i]);

                if (VAR_4 < 0) {

                    goto fail;

                }

                s->offsets[i] += last_in_offset;

                offset += 8;



                VAR_4 = read_uint64(VAR_0, offset, &s->lengths[i]);

                if (VAR_4 < 0) {

                    goto fail;

                }

                offset += 8;



                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);

                    VAR_4 = -EINVAL;

                    goto fail;

                }



                update_max_chunk_size(s, i, &max_compressed_size,

                                      &max_sectors_per_chunk);

            }

            s->n_chunks += chunk_count;

        }

    }



    

    s->compressed_chunk = qemu_try_blockalign(VAR_0->file,

                                              max_compressed_size + 1);

    s->uncompressed_chunk = qemu_try_blockalign(VAR_0->file,

                                                512 * max_sectors_per_chunk);

    if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) {

        VAR_4 = -ENOMEM;

        goto fail;

    }



    if (inflateInit(&s->zstream) != Z_OK) {

        VAR_4 = -EINVAL;

        goto fail;

    }



    s->current_chunk = s->n_chunks;



    qemu_co_mutex_init(&s->lock);

    return 0;



fail:

    g_free(s->types);

    g_free(s->offsets);

    g_free(s->lengths);

    g_free(s->sectors);

    g_free(s->sectorcounts);

    qemu_vfree(s->compressed_chunk);

    qemu_vfree(s->uncompressed_chunk);

    return VAR_4;

}

static int FUNC_0(BlockDriverState *VAR_0, QDict *VAR_1, int VAR_2,
Error **VAR_3)
{ BDRVDMGState *s = VAR_0->opaque; uint64_t info_begin, info_end, last_in_offset, last_out_offset; uint32_t count, tmp; uint32_t max_compressed_size = 1, max_sectors_per_chunk = 1, i; int64_t offset; int VAR_4; VAR_0->read_only = 1; s->n_chunks = 0; s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; offset = bdrv_getlength(VAR_0->file); if (offset < 0) { VAR_4 = offset; goto fail; } offset -= 0x1d8; VAR_4 = read_uint64(VAR_0, offset, &info_begin); if (VAR_4 < 0) { goto fail; } else if (info_begin == 0) { VAR_4 = -EINVAL; goto fail; } VAR_4 = read_uint32(VAR_0, info_begin, &tmp); if (VAR_4 < 0) { goto fail; } else if (tmp != 0x100) { VAR_4 = -EINVAL; goto fail; } VAR_4 = read_uint32(VAR_0, info_begin + 4, &count); if (VAR_4 < 0) { goto fail; } else if (count == 0) { VAR_4 = -EINVAL; goto fail; } info_end = info_begin + count; offset = info_begin + 0x100; last_in_offset = last_out_offset = 0; while (offset < info_end) { uint32_t type; VAR_4 = read_uint32(VAR_0, offset, &count); if (VAR_4 < 0) { goto fail; } else if (count == 0) { VAR_4 = -EINVAL; goto fail; } offset += 4; VAR_4 = read_uint32(VAR_0, offset, &type); if (VAR_4 < 0) { goto fail; } if (type == 0x6d697368 && count >= 244) { size_t new_size; uint32_t chunk_count; offset += 4; offset += 200; 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++) { VAR_4 = read_uint32(VAR_0, offset, &s->types[i]); if (VAR_4 < 0) { goto fail; } offset += 4; if (s->types[i] != 0x80000005 && s->types[i] != 1 &&
s->types[i] != 2) { if (s->types[i] == 0xffffffff && i > 0) { last_in_offset = s->offsets[i - 1] + s->lengths[i - 1]; last_out_offset = s->sectors[i - 1] +
s->sectorcounts[i - 1]; } chunk_count--; i--; offset += 36; continue; } offset += 4; VAR_4 = read_uint64(VAR_0, offset, &s->sectors[i]); if (VAR_4 < 0) { goto fail; } s->sectors[i] += last_out_offset; offset += 8; VAR_4 = read_uint64(VAR_0, offset, &s->sectorcounts[i]); if (VAR_4 < 0) { goto fail; } offset += 8; if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) { error_report("sector count %" PRIu64 " for chunk %" PRIu32
" is larger than max (%u)",
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX); VAR_4 = -EINVAL; goto fail; } VAR_4 = read_uint64(VAR_0, offset, &s->offsets[i]); if (VAR_4 < 0) { goto fail; } s->offsets[i] += last_in_offset; offset += 8; VAR_4 = read_uint64(VAR_0, offset, &s->lengths[i]); if (VAR_4 < 0) { goto fail; } offset += 8; 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); VAR_4 = -EINVAL; goto fail; } update_max_chunk_size(s, i, &max_compressed_size,
&max_sectors_per_chunk); } s->n_chunks += chunk_count; } } s->compressed_chunk = qemu_try_blockalign(VAR_0->file,
max_compressed_size + 1); s->uncompressed_chunk = qemu_try_blockalign(VAR_0->file,
512 * max_sectors_per_chunk); if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) { VAR_4 = -ENOMEM; goto fail; } if (inflateInit(&s->zstream) != Z_OK) { VAR_4 = -EINVAL; goto fail; } s->current_chunk = s->n_chunks; qemu_co_mutex_init(&s->lock); return 0; fail:
g_free(s->types); g_free(s->offsets); g_free(s->lengths); g_free(s->sectors); g_free(s->sectorcounts); qemu_vfree(s->compressed_chunk); qemu_vfree(s->uncompressed_chunk); return VAR_4; }