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

                     Error **errp)

{

    BDRVVHDXState *s = bs->opaque;

    int ret = 0;

    uint32_t i;

    uint64_t signature;

    uint32_t data_blocks_cnt, bitmap_blocks_cnt;





    s->bat = NULL;

    s->first_visible_write = true;



    qemu_co_mutex_init(&s->lock);



    /* validate the file signature */

    ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t));

    if (ret < 0) {

        goto fail;

    }

    if (memcmp(&signature, "vhdxfile", 8)) {

        ret = -EINVAL;

        goto fail;

    }



    /* This is used for any header updates, for the file_write_guid.

     * The spec dictates that a new value should be used for the first

     * header update */

    vhdx_guid_generate(&s->session_guid);



    ret = vhdx_parse_header(bs, s);

    if (ret) {

        goto fail;

    }



    ret = vhdx_parse_log(bs, s);

    if (ret) {

        goto fail;

    }



    ret = vhdx_open_region_tables(bs, s);

    if (ret) {

        goto fail;

    }



    ret = vhdx_parse_metadata(bs, s);

    if (ret) {

        goto fail;

    }

    s->block_size = s->params.block_size;



    /* the VHDX spec dictates that virtual_disk_size is always a multiple of

     * logical_sector_size */

    bs->total_sectors = s->virtual_disk_size >> s->logical_sector_size_bits;



    data_blocks_cnt = s->virtual_disk_size >> s->block_size_bits;

    if (s->virtual_disk_size - (data_blocks_cnt << s->block_size_bits)) {

        data_blocks_cnt++;

    }

    bitmap_blocks_cnt = data_blocks_cnt >> s->chunk_ratio_bits;

    if (data_blocks_cnt - (bitmap_blocks_cnt << s->chunk_ratio_bits)) {

        bitmap_blocks_cnt++;

    }



    if (s->parent_entries) {

        s->bat_entries = bitmap_blocks_cnt * (s->chunk_ratio + 1);

    } else {

        s->bat_entries = data_blocks_cnt +

                         ((data_blocks_cnt - 1) >> s->chunk_ratio_bits);

    }



    s->bat_offset = s->bat_rt.file_offset;



    if (s->bat_entries > s->bat_rt.length / sizeof(VHDXBatEntry)) {

        /* BAT allocation is not large enough for all entries */

        ret = -EINVAL;

        goto fail;

    }



    /* s->bat is freed in vhdx_close() */

    s->bat = qemu_blockalign(bs, s->bat_rt.length);



    ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length);

    if (ret < 0) {

        goto fail;

    }



    for (i = 0; i < s->bat_entries; i++) {

        le64_to_cpus(&s->bat[i]);

    }



    if (flags & BDRV_O_RDWR) {

        ret = vhdx_update_headers(bs, s, false, NULL);

        if (ret < 0) {

            goto fail;

        }

    }



    /* TODO: differencing files, write */



    /* Disable migration when VHDX images are used */

    error_set(&s->migration_blocker,

            QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,

            "vhdx", bs->device_name, "live migration");

    migrate_add_blocker(s->migration_blocker);



    return 0;

fail:

    qemu_vfree(s->headers[0]);

    qemu_vfree(s->headers[1]);

    qemu_vfree(s->bat);

    qemu_vfree(s->parent_entries);

    return ret;

}

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

                     Error **errp)

{

    BDRVVHDXState *s = bs->opaque;

    int ret = 0;

    uint32_t i;

    uint64_t signature;

    uint32_t data_blocks_cnt, bitmap_blocks_cnt;





    s->bat = NULL;

    s->first_visible_write = true;



    qemu_co_mutex_init(&s->lock);



    

    ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t));

    if (ret < 0) {

        goto fail;

    }

    if (memcmp(&signature, "vhdxfile", 8)) {

        ret = -EINVAL;

        goto fail;

    }



    





    vhdx_guid_generate(&s->session_guid);



    ret = vhdx_parse_header(bs, s);

    if (ret) {

        goto fail;

    }



    ret = vhdx_parse_log(bs, s);

    if (ret) {

        goto fail;

    }



    ret = vhdx_open_region_tables(bs, s);

    if (ret) {

        goto fail;

    }



    ret = vhdx_parse_metadata(bs, s);

    if (ret) {

        goto fail;

    }

    s->block_size = s->params.block_size;



    



    bs->total_sectors = s->virtual_disk_size >> s->logical_sector_size_bits;



    data_blocks_cnt = s->virtual_disk_size >> s->block_size_bits;

    if (s->virtual_disk_size - (data_blocks_cnt << s->block_size_bits)) {

        data_blocks_cnt++;

    }

    bitmap_blocks_cnt = data_blocks_cnt >> s->chunk_ratio_bits;

    if (data_blocks_cnt - (bitmap_blocks_cnt << s->chunk_ratio_bits)) {

        bitmap_blocks_cnt++;

    }



    if (s->parent_entries) {

        s->bat_entries = bitmap_blocks_cnt * (s->chunk_ratio + 1);

    } else {

        s->bat_entries = data_blocks_cnt +

                         ((data_blocks_cnt - 1) >> s->chunk_ratio_bits);

    }



    s->bat_offset = s->bat_rt.file_offset;



    if (s->bat_entries > s->bat_rt.length / sizeof(VHDXBatEntry)) {

        

        ret = -EINVAL;

        goto fail;

    }



    

    s->bat = qemu_blockalign(bs, s->bat_rt.length);



    ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length);

    if (ret < 0) {

        goto fail;

    }



    for (i = 0; i < s->bat_entries; i++) {

        le64_to_cpus(&s->bat[i]);

    }



    if (flags & BDRV_O_RDWR) {

        ret = vhdx_update_headers(bs, s, false, NULL);

        if (ret < 0) {

            goto fail;

        }

    }



    



    

    error_set(&s->migration_blocker,

            QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,

            "vhdx", bs->device_name, "live migration");

    migrate_add_blocker(s->migration_blocker);



    return 0;

fail:

    qemu_vfree(s->headers[0]);

    qemu_vfree(s->headers[1]);

    qemu_vfree(s->bat);

    qemu_vfree(s->parent_entries);

    return ret;

}

static int FUNC_0(BlockDriverState *VAR_0, QDict *VAR_1, int VAR_2,

                     Error **VAR_3)

{

    BDRVVHDXState *s = VAR_0->opaque;

    int VAR_4 = 0;

    uint32_t i;

    uint64_t signature;

    uint32_t data_blocks_cnt, bitmap_blocks_cnt;





    s->bat = NULL;

    s->first_visible_write = true;



    qemu_co_mutex_init(&s->lock);



    

    VAR_4 = bdrv_pread(VAR_0->file, 0, &signature, sizeof(uint64_t));

    if (VAR_4 < 0) {

        goto fail;

    }

    if (memcmp(&signature, "vhdxfile", 8)) {

        VAR_4 = -EINVAL;

        goto fail;

    }



    





    vhdx_guid_generate(&s->session_guid);



    VAR_4 = vhdx_parse_header(VAR_0, s);

    if (VAR_4) {

        goto fail;

    }



    VAR_4 = vhdx_parse_log(VAR_0, s);

    if (VAR_4) {

        goto fail;

    }



    VAR_4 = vhdx_open_region_tables(VAR_0, s);

    if (VAR_4) {

        goto fail;

    }



    VAR_4 = vhdx_parse_metadata(VAR_0, s);

    if (VAR_4) {

        goto fail;

    }

    s->block_size = s->params.block_size;



    



    VAR_0->total_sectors = s->virtual_disk_size >> s->logical_sector_size_bits;



    data_blocks_cnt = s->virtual_disk_size >> s->block_size_bits;

    if (s->virtual_disk_size - (data_blocks_cnt << s->block_size_bits)) {

        data_blocks_cnt++;

    }

    bitmap_blocks_cnt = data_blocks_cnt >> s->chunk_ratio_bits;

    if (data_blocks_cnt - (bitmap_blocks_cnt << s->chunk_ratio_bits)) {

        bitmap_blocks_cnt++;

    }



    if (s->parent_entries) {

        s->bat_entries = bitmap_blocks_cnt * (s->chunk_ratio + 1);

    } else {

        s->bat_entries = data_blocks_cnt +

                         ((data_blocks_cnt - 1) >> s->chunk_ratio_bits);

    }



    s->bat_offset = s->bat_rt.file_offset;



    if (s->bat_entries > s->bat_rt.length / sizeof(VHDXBatEntry)) {

        

        VAR_4 = -EINVAL;

        goto fail;

    }



    

    s->bat = qemu_blockalign(VAR_0, s->bat_rt.length);



    VAR_4 = bdrv_pread(VAR_0->file, s->bat_offset, s->bat, s->bat_rt.length);

    if (VAR_4 < 0) {

        goto fail;

    }



    for (i = 0; i < s->bat_entries; i++) {

        le64_to_cpus(&s->bat[i]);

    }



    if (VAR_2 & BDRV_O_RDWR) {

        VAR_4 = vhdx_update_headers(VAR_0, s, false, NULL);

        if (VAR_4 < 0) {

            goto fail;

        }

    }



    



    

    error_set(&s->migration_blocker,

            QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,

            "vhdx", VAR_0->device_name, "live migration");

    migrate_add_blocker(s->migration_blocker);



    return 0;

fail:

    qemu_vfree(s->headers[0]);

    qemu_vfree(s->headers[1]);

    qemu_vfree(s->bat);

    qemu_vfree(s->parent_entries);

    return VAR_4;

}

static int FUNC_0(BlockDriverState *VAR_0, QDict *VAR_1, int VAR_2,
Error **VAR_3)
{ BDRVVHDXState *s = VAR_0->opaque; int VAR_4 = 0; uint32_t i; uint64_t signature; uint32_t data_blocks_cnt, bitmap_blocks_cnt; s->bat = NULL; s->first_visible_write = true; qemu_co_mutex_init(&s->lock); VAR_4 = bdrv_pread(VAR_0->file, 0, &signature, sizeof(uint64_t)); if (VAR_4 < 0) { goto fail; } if (memcmp(&signature, "vhdxfile", 8)) { VAR_4 = -EINVAL; goto fail; } vhdx_guid_generate(&s->session_guid); VAR_4 = vhdx_parse_header(VAR_0, s); if (VAR_4) { goto fail; } VAR_4 = vhdx_parse_log(VAR_0, s); if (VAR_4) { goto fail; } VAR_4 = vhdx_open_region_tables(VAR_0, s); if (VAR_4) { goto fail; } VAR_4 = vhdx_parse_metadata(VAR_0, s); if (VAR_4) { goto fail; } s->block_size = s->params.block_size; VAR_0->total_sectors = s->virtual_disk_size >> s->logical_sector_size_bits; data_blocks_cnt = s->virtual_disk_size >> s->block_size_bits; if (s->virtual_disk_size - (data_blocks_cnt << s->block_size_bits)) { data_blocks_cnt++; } bitmap_blocks_cnt = data_blocks_cnt >> s->chunk_ratio_bits; if (data_blocks_cnt - (bitmap_blocks_cnt << s->chunk_ratio_bits)) { bitmap_blocks_cnt++; } if (s->parent_entries) { s->bat_entries = bitmap_blocks_cnt * (s->chunk_ratio + 1); } else { s->bat_entries = data_blocks_cnt +
((data_blocks_cnt - 1) >> s->chunk_ratio_bits); } s->bat_offset = s->bat_rt.file_offset; if (s->bat_entries > s->bat_rt.length / sizeof(VHDXBatEntry)) { VAR_4 = -EINVAL; goto fail; } s->bat = qemu_blockalign(VAR_0, s->bat_rt.length); VAR_4 = bdrv_pread(VAR_0->file, s->bat_offset, s->bat, s->bat_rt.length); if (VAR_4 < 0) { goto fail; } for (i = 0; i < s->bat_entries; i++) { le64_to_cpus(&s->bat[i]); } if (VAR_2 & BDRV_O_RDWR) { VAR_4 = vhdx_update_headers(VAR_0, s, false, NULL); if (VAR_4 < 0) { goto fail; } } error_set(&s->migration_blocker,
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
"vhdx", VAR_0->device_name, "live migration"); migrate_add_blocker(s->migration_blocker); return 0; fail:
qemu_vfree(s->headers[0]); qemu_vfree(s->headers[1]); qemu_vfree(s->bat); qemu_vfree(s->parent_entries); return VAR_4; }