static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,

                                       Error **errp)

{

    Error *local_err = NULL;

    BlockMeasureInfo *info;

    uint64_t required = 0; /* bytes that contribute to required size */

    uint64_t virtual_size; /* disk size as seen by guest */

    uint64_t refcount_bits;

    uint64_t l2_tables;

    size_t cluster_size;

    int version;

    char *optstr;

    PreallocMode prealloc;

    bool has_backing_file;



    /* Parse image creation options */

    cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);

    if (local_err) {

        goto err;

    }



    version = qcow2_opt_get_version_del(opts, &local_err);

    if (local_err) {

        goto err;

    }



    refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);

    if (local_err) {

        goto err;

    }



    optstr = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);

    prealloc = qapi_enum_parse(&PreallocMode_lookup, optstr,

                               PREALLOC_MODE_OFF, &local_err);

    g_free(optstr);

    if (local_err) {

        goto err;

    }



    optstr = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);

    has_backing_file = !!optstr;

    g_free(optstr);



    virtual_size = align_offset(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),

                                cluster_size);



    /* Check that virtual disk size is valid */

    l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,

                             cluster_size / sizeof(uint64_t));

    if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) {

        error_setg(&local_err, "The image size is too large "

                               "(try using a larger cluster size)");

        goto err;

    }



    /* Account for input image */

    if (in_bs) {

        int64_t ssize = bdrv_getlength(in_bs);

        if (ssize < 0) {

            error_setg_errno(&local_err, -ssize,

                             "Unable to get image virtual_size");

            goto err;

        }



        virtual_size = align_offset(ssize, cluster_size);



        if (has_backing_file) {

            /* We don't how much of the backing chain is shared by the input

             * image and the new image file.  In the worst case the new image's

             * backing file has nothing in common with the input image.  Be

             * conservative and assume all clusters need to be written.

             */

            required = virtual_size;

        } else {

            int64_t offset;

            int pnum = 0;



            for (offset = 0; offset < ssize;

                 offset += pnum * BDRV_SECTOR_SIZE) {

                int nb_sectors = MIN(ssize - offset,

                                     BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;

                BlockDriverState *file;

                int64_t ret;



                ret = bdrv_get_block_status_above(in_bs, NULL,

                                                  offset >> BDRV_SECTOR_BITS,

                                                  nb_sectors,

                                                  &pnum, &file);

                if (ret < 0) {

                    error_setg_errno(&local_err, -ret,

                                     "Unable to get block status");

                    goto err;

                }



                if (ret & BDRV_BLOCK_ZERO) {

                    /* Skip zero regions (safe with no backing file) */

                } else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) ==

                           (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {

                    /* Extend pnum to end of cluster for next iteration */

                    pnum = (ROUND_UP(offset + pnum * BDRV_SECTOR_SIZE,

                                 cluster_size) - offset) >> BDRV_SECTOR_BITS;



                    /* Count clusters we've seen */

                    required += offset % cluster_size + pnum * BDRV_SECTOR_SIZE;

                }

            }

        }

    }



    /* Take into account preallocation.  Nothing special is needed for

     * PREALLOC_MODE_METADATA since metadata is always counted.

     */

    if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {

        required = virtual_size;

    }



    info = g_new(BlockMeasureInfo, 1);

    info->fully_allocated =

        qcow2_calc_prealloc_size(virtual_size, cluster_size,

                                 ctz32(refcount_bits));



    /* Remove data clusters that are not required.  This overestimates the

     * required size because metadata needed for the fully allocated file is

     * still counted.

     */

    info->required = info->fully_allocated - virtual_size + required;

    return info;



err:

    error_propagate(errp, local_err);

    return NULL;

}

static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,

                                       Error **errp)

{

    Error *local_err = NULL;

    BlockMeasureInfo *info;

    uint64_t required = 0; 

    uint64_t virtual_size; 

    uint64_t refcount_bits;

    uint64_t l2_tables;

    size_t cluster_size;

    int version;

    char *optstr;

    PreallocMode prealloc;

    bool has_backing_file;



    

    cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);

    if (local_err) {

        goto err;

    }



    version = qcow2_opt_get_version_del(opts, &local_err);

    if (local_err) {

        goto err;

    }



    refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);

    if (local_err) {

        goto err;

    }



    optstr = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);

    prealloc = qapi_enum_parse(&PreallocMode_lookup, optstr,

                               PREALLOC_MODE_OFF, &local_err);

    g_free(optstr);

    if (local_err) {

        goto err;

    }



    optstr = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);

    has_backing_file = !!optstr;

    g_free(optstr);



    virtual_size = align_offset(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),

                                cluster_size);



    

    l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,

                             cluster_size / sizeof(uint64_t));

    if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) {

        error_setg(&local_err, "The image size is too large "

                               "(try using a larger cluster size)");

        goto err;

    }



    

    if (in_bs) {

        int64_t ssize = bdrv_getlength(in_bs);

        if (ssize < 0) {

            error_setg_errno(&local_err, -ssize,

                             "Unable to get image virtual_size");

            goto err;

        }



        virtual_size = align_offset(ssize, cluster_size);



        if (has_backing_file) {

            









            required = virtual_size;

        } else {

            int64_t offset;

            int pnum = 0;



            for (offset = 0; offset < ssize;

                 offset += pnum * BDRV_SECTOR_SIZE) {

                int nb_sectors = MIN(ssize - offset,

                                     BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;

                BlockDriverState *file;

                int64_t ret;



                ret = bdrv_get_block_status_above(in_bs, NULL,

                                                  offset >> BDRV_SECTOR_BITS,

                                                  nb_sectors,

                                                  &pnum, &file);

                if (ret < 0) {

                    error_setg_errno(&local_err, -ret,

                                     "Unable to get block status");

                    goto err;

                }



                if (ret & BDRV_BLOCK_ZERO) {

                    

                } else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) ==

                           (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {

                    

                    pnum = (ROUND_UP(offset + pnum * BDRV_SECTOR_SIZE,

                                 cluster_size) - offset) >> BDRV_SECTOR_BITS;



                    

                    required += offset % cluster_size + pnum * BDRV_SECTOR_SIZE;

                }

            }

        }

    }



    





    if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {

        required = virtual_size;

    }



    info = g_new(BlockMeasureInfo, 1);

    info->fully_allocated =

        qcow2_calc_prealloc_size(virtual_size, cluster_size,

                                 ctz32(refcount_bits));



    







    info->required = info->fully_allocated - virtual_size + required;

    return info;



err:

    error_propagate(errp, local_err);

    return NULL;

}

static BlockMeasureInfo *FUNC_0(QemuOpts *opts, BlockDriverState *in_bs,

                                       Error **errp)

{

    Error *local_err = NULL;

    BlockMeasureInfo *info;

    uint64_t required = 0; 

    uint64_t virtual_size; 

    uint64_t refcount_bits;

    uint64_t l2_tables;

    size_t cluster_size;

    int VAR_0;

    char *VAR_1;

    PreallocMode prealloc;

    bool has_backing_file;



    

    cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);

    if (local_err) {

        goto err;

    }



    VAR_0 = qcow2_opt_get_version_del(opts, &local_err);

    if (local_err) {

        goto err;

    }



    refcount_bits = qcow2_opt_get_refcount_bits_del(opts, VAR_0, &local_err);

    if (local_err) {

        goto err;

    }



    VAR_1 = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);

    prealloc = qapi_enum_parse(&PreallocMode_lookup, VAR_1,

                               PREALLOC_MODE_OFF, &local_err);

    g_free(VAR_1);

    if (local_err) {

        goto err;

    }



    VAR_1 = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);

    has_backing_file = !!VAR_1;

    g_free(VAR_1);



    virtual_size = align_offset(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),

                                cluster_size);



    

    l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,

                             cluster_size / sizeof(uint64_t));

    if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) {

        error_setg(&local_err, "The image size is too large "

                               "(try using a larger cluster size)");

        goto err;

    }



    

    if (in_bs) {

        int64_t ssize = bdrv_getlength(in_bs);

        if (ssize < 0) {

            error_setg_errno(&local_err, -ssize,

                             "Unable to get image virtual_size");

            goto err;

        }



        virtual_size = align_offset(ssize, cluster_size);



        if (has_backing_file) {

            









            required = virtual_size;

        } else {

            int64_t offset;

            int VAR_2 = 0;



            for (offset = 0; offset < ssize;

                 offset += VAR_2 * BDRV_SECTOR_SIZE) {

                int nb_sectors = MIN(ssize - offset,

                                     BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;

                BlockDriverState *file;

                int64_t ret;



                ret = bdrv_get_block_status_above(in_bs, NULL,

                                                  offset >> BDRV_SECTOR_BITS,

                                                  nb_sectors,

                                                  &VAR_2, &file);

                if (ret < 0) {

                    error_setg_errno(&local_err, -ret,

                                     "Unable to get block status");

                    goto err;

                }



                if (ret & BDRV_BLOCK_ZERO) {

                    

                } else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) ==

                           (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {

                    

                    VAR_2 = (ROUND_UP(offset + VAR_2 * BDRV_SECTOR_SIZE,

                                 cluster_size) - offset) >> BDRV_SECTOR_BITS;



                    

                    required += offset % cluster_size + VAR_2 * BDRV_SECTOR_SIZE;

                }

            }

        }

    }



    





    if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {

        required = virtual_size;

    }



    info = g_new(BlockMeasureInfo, 1);

    info->fully_allocated =

        qcow2_calc_prealloc_size(virtual_size, cluster_size,

                                 ctz32(refcount_bits));



    







    info->required = info->fully_allocated - virtual_size + required;

    return info;



err:

    error_propagate(errp, local_err);

    return NULL;

}

static BlockMeasureInfo *FUNC_0(QemuOpts *opts, BlockDriverState *in_bs,
Error **errp)
{ Error *local_err = NULL; BlockMeasureInfo *info; uint64_t required = 0; uint64_t virtual_size; uint64_t refcount_bits; uint64_t l2_tables; size_t cluster_size; int VAR_0; char *VAR_1; PreallocMode prealloc; bool has_backing_file; cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err); if (local_err) { goto err; } VAR_0 = qcow2_opt_get_version_del(opts, &local_err); if (local_err) { goto err; } refcount_bits = qcow2_opt_get_refcount_bits_del(opts, VAR_0, &local_err); if (local_err) { goto err; } VAR_1 = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); prealloc = qapi_enum_parse(&PreallocMode_lookup, VAR_1,
PREALLOC_MODE_OFF, &local_err); g_free(VAR_1); if (local_err) { goto err; } VAR_1 = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); has_backing_file = !!VAR_1; g_free(VAR_1); virtual_size = align_offset(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
cluster_size); l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,
cluster_size / sizeof(uint64_t)); if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) { error_setg(&local_err, "The image size is too large "
"(try using a larger cluster size)"); goto err; } if (in_bs) { int64_t ssize = bdrv_getlength(in_bs); if (ssize < 0) { error_setg_errno(&local_err, -ssize,
"Unable to get image virtual_size"); goto err; } virtual_size = align_offset(ssize, cluster_size); if (has_backing_file) { required = virtual_size; } else { int64_t offset; int VAR_2 = 0; for (offset = 0; offset < ssize; offset += VAR_2 * BDRV_SECTOR_SIZE) { int nb_sectors = MIN(ssize - offset,
BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE; BlockDriverState *file; int64_t ret; ret = bdrv_get_block_status_above(in_bs, NULL,
offset >> BDRV_SECTOR_BITS,
nb_sectors,
&VAR_2, &file); if (ret < 0) { error_setg_errno(&local_err, -ret,
"Unable to get block status"); goto err; } if (ret & BDRV_BLOCK_ZERO) { } else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) == (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) { VAR_2 = (ROUND_UP(offset + VAR_2 * BDRV_SECTOR_SIZE,
cluster_size) - offset) >> BDRV_SECTOR_BITS; required += offset % cluster_size + VAR_2 * BDRV_SECTOR_SIZE; } } } } if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) { required = virtual_size; } info = g_new(BlockMeasureInfo, 1); info->fully_allocated =
qcow2_calc_prealloc_size(virtual_size, cluster_size,
ctz32(refcount_bits)); info->required = info->fully_allocated - virtual_size + required; return info; err:
error_propagate(errp, local_err); return NULL; }