int bdrv_snapshot_goto(BlockDriverState *bs,

                       const char *snapshot_id,

                       Error **errp)

{

    BlockDriver *drv = bs->drv;

    int ret, open_ret;

    int64_t len;



    if (!drv) {

        error_setg(errp, "Block driver is closed");

        return -ENOMEDIUM;

    }



    len = bdrv_getlength(bs);

    if (len < 0) {

        error_setg_errno(errp, -len, "Cannot get block device size");

        return len;

    }

    /* We should set all bits in all enabled dirty bitmaps, because dirty

     * bitmaps reflect active state of disk and snapshot switch operation

     * actually dirties active state.

     * TODO: It may make sense not to set all bits but analyze block status of

     * current state and destination snapshot and do not set bits corresponding

     * to both-zero or both-unallocated areas. */

    bdrv_set_dirty(bs, 0, len);



    if (drv->bdrv_snapshot_goto) {

        ret = drv->bdrv_snapshot_goto(bs, snapshot_id);

        if (ret < 0) {

            error_setg_errno(errp, -ret, "Failed to load snapshot");

        }

        return ret;

    }



    if (bs->file) {

        BlockDriverState *file;

        QDict *options = qdict_clone_shallow(bs->options);

        QDict *file_options;

        Error *local_err = NULL;



        file = bs->file->bs;

        /* Prevent it from getting deleted when detached from bs */

        bdrv_ref(file);



        qdict_extract_subqdict(options, &file_options, "file.");

        QDECREF(file_options);

        qdict_put_str(options, "file", bdrv_get_node_name(file));



        drv->bdrv_close(bs);

        bdrv_unref_child(bs, bs->file);

        bs->file = NULL;



        ret = bdrv_snapshot_goto(file, snapshot_id, errp);

        open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);

        QDECREF(options);

        if (open_ret < 0) {

            bdrv_unref(file);

            bs->drv = NULL;

            /* A bdrv_snapshot_goto() error takes precedence */

            error_propagate(errp, local_err);

            return ret < 0 ? ret : open_ret;

        }



        assert(bs->file->bs == file);

        bdrv_unref(file);

        return ret;

    }



    error_setg(errp, "Block driver does not support snapshots");

    return -ENOTSUP;

}

int bdrv_snapshot_goto(BlockDriverState *bs,

                       const char *snapshot_id,

                       Error **errp)

{

    BlockDriver *drv = bs->drv;

    int ret, open_ret;

    int64_t len;



    if (!drv) {

        error_setg(errp, "Block driver is closed");

        return -ENOMEDIUM;

    }



    len = bdrv_getlength(bs);

    if (len < 0) {

        error_setg_errno(errp, -len, "Cannot get block device size");

        return len;

    }

    











    bdrv_set_dirty(bs, 0, len);



    if (drv->bdrv_snapshot_goto) {

        ret = drv->bdrv_snapshot_goto(bs, snapshot_id);

        if (ret < 0) {

            error_setg_errno(errp, -ret, "Failed to load snapshot");

        }

        return ret;

    }



    if (bs->file) {

        BlockDriverState *file;

        QDict *options = qdict_clone_shallow(bs->options);

        QDict *file_options;

        Error *local_err = NULL;



        file = bs->file->bs;

        

        bdrv_ref(file);



        qdict_extract_subqdict(options, &file_options, "file.");

        QDECREF(file_options);

        qdict_put_str(options, "file", bdrv_get_node_name(file));



        drv->bdrv_close(bs);

        bdrv_unref_child(bs, bs->file);

        bs->file = NULL;



        ret = bdrv_snapshot_goto(file, snapshot_id, errp);

        open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);

        QDECREF(options);

        if (open_ret < 0) {

            bdrv_unref(file);

            bs->drv = NULL;

            

            error_propagate(errp, local_err);

            return ret < 0 ? ret : open_ret;

        }



        assert(bs->file->bs == file);

        bdrv_unref(file);

        return ret;

    }



    error_setg(errp, "Block driver does not support snapshots");

    return -ENOTSUP;

}

int FUNC_0(BlockDriverState *VAR_0,

                       const char *VAR_1,

                       Error **VAR_2)

{

    BlockDriver *drv = VAR_0->drv;

    int VAR_3, VAR_4;

    int64_t len;



    if (!drv) {

        error_setg(VAR_2, "Block driver is closed");

        return -ENOMEDIUM;

    }



    len = bdrv_getlength(VAR_0);

    if (len < 0) {

        error_setg_errno(VAR_2, -len, "Cannot get block device size");

        return len;

    }

    











    bdrv_set_dirty(VAR_0, 0, len);



    if (drv->FUNC_0) {

        VAR_3 = drv->FUNC_0(VAR_0, VAR_1);

        if (VAR_3 < 0) {

            error_setg_errno(VAR_2, -VAR_3, "Failed to load snapshot");

        }

        return VAR_3;

    }



    if (VAR_0->file) {

        BlockDriverState *file;

        QDict *options = qdict_clone_shallow(VAR_0->options);

        QDict *file_options;

        Error *local_err = NULL;



        file = VAR_0->file->VAR_0;

        

        bdrv_ref(file);



        qdict_extract_subqdict(options, &file_options, "file.");

        QDECREF(file_options);

        qdict_put_str(options, "file", bdrv_get_node_name(file));



        drv->bdrv_close(VAR_0);

        bdrv_unref_child(VAR_0, VAR_0->file);

        VAR_0->file = NULL;



        VAR_3 = FUNC_0(file, VAR_1, VAR_2);

        VAR_4 = drv->bdrv_open(VAR_0, options, VAR_0->open_flags, &local_err);

        QDECREF(options);

        if (VAR_4 < 0) {

            bdrv_unref(file);

            VAR_0->drv = NULL;

            

            error_propagate(VAR_2, local_err);

            return VAR_3 < 0 ? VAR_3 : VAR_4;

        }



        assert(VAR_0->file->VAR_0 == file);

        bdrv_unref(file);

        return VAR_3;

    }



    error_setg(VAR_2, "Block driver does not support snapshots");

    return -ENOTSUP;

}

int FUNC_0(BlockDriverState *VAR_0,
const char *VAR_1,
Error **VAR_2)
{ BlockDriver *drv = VAR_0->drv; int VAR_3, VAR_4; int64_t len; if (!drv) { error_setg(VAR_2, "Block driver is closed"); return -ENOMEDIUM; } len = bdrv_getlength(VAR_0); if (len < 0) { error_setg_errno(VAR_2, -len, "Cannot get block device size"); return len; } bdrv_set_dirty(VAR_0, 0, len); if (drv->FUNC_0) { VAR_3 = drv->FUNC_0(VAR_0, VAR_1); if (VAR_3 < 0) { error_setg_errno(VAR_2, -VAR_3, "Failed to load snapshot"); } return VAR_3; } if (VAR_0->file) { BlockDriverState *file; QDict *options = qdict_clone_shallow(VAR_0->options); QDict *file_options; Error *local_err = NULL; file = VAR_0->file->VAR_0; bdrv_ref(file); qdict_extract_subqdict(options, &file_options, "file."); QDECREF(file_options); qdict_put_str(options, "file", bdrv_get_node_name(file)); drv->bdrv_close(VAR_0); bdrv_unref_child(VAR_0, VAR_0->file); VAR_0->file = NULL; VAR_3 = FUNC_0(file, VAR_1, VAR_2); VAR_4 = drv->bdrv_open(VAR_0, options, VAR_0->open_flags, &local_err); QDECREF(options); if (VAR_4 < 0) { bdrv_unref(file); VAR_0->drv = NULL; error_propagate(VAR_2, local_err); return VAR_3 < 0 ? VAR_3 : VAR_4; } assert(VAR_0->file->VAR_0 == file); bdrv_unref(file); return VAR_3; } error_setg(VAR_2, "Block driver does not support snapshots"); return -ENOTSUP; }