int bdrv_open(BlockDriverState **pbs, const char *filename,

              const char *reference, QDict *options, int flags,

              BlockDriver *drv, Error **errp)

{

    int ret;

    BlockDriverState *file = NULL, *bs;

    const char *drvname;

    Error *local_err = NULL;

    int snapshot_flags = 0;



    assert(pbs);



    if (reference) {

        bool options_non_empty = options ? qdict_size(options) : false;

        QDECREF(options);



        if (*pbs) {

            error_setg(errp, "Cannot reuse an existing BDS when referencing "

                       "another block device");

            return -EINVAL;

        }



        if (filename || options_non_empty) {

            error_setg(errp, "Cannot reference an existing block device with "

                       "additional options or a new filename");

            return -EINVAL;

        }



        bs = bdrv_lookup_bs(reference, reference, errp);

        if (!bs) {

            return -ENODEV;

        }

        bdrv_ref(bs);

        *pbs = bs;

        return 0;

    }



    if (*pbs) {

        bs = *pbs;

    } else {

        bs = bdrv_new();

    }



    /* NULL means an empty set of options */

    if (options == NULL) {

        options = qdict_new();

    }



    ret = bdrv_fill_options(&options, &filename, flags, drv, &local_err);

    if (local_err) {

        goto fail;

    }



    /* Find the right image format driver */

    drv = NULL;

    drvname = qdict_get_try_str(options, "driver");

    if (drvname) {

        drv = bdrv_find_format(drvname);

        qdict_del(options, "driver");

        if (!drv) {

            error_setg(errp, "Unknown driver: '%s'", drvname);

            ret = -EINVAL;

            goto fail;

        }

    }



    assert(drvname || !(flags & BDRV_O_PROTOCOL));

    if (drv && !drv->bdrv_file_open) {

        /* If the user explicitly wants a format driver here, we'll need to add

         * another layer for the protocol in bs->file */

        flags &= ~BDRV_O_PROTOCOL;

    }



    bs->options = options;

    options = qdict_clone_shallow(options);



    /* Open image file without format layer */

    if ((flags & BDRV_O_PROTOCOL) == 0) {

        if (flags & BDRV_O_RDWR) {

            flags |= BDRV_O_ALLOW_RDWR;

        }

        if (flags & BDRV_O_SNAPSHOT) {

            snapshot_flags = bdrv_temp_snapshot_flags(flags);

            flags = bdrv_backing_flags(flags);

        }



        assert(file == NULL);

        ret = bdrv_open_image(&file, filename, options, "file",

                              bdrv_inherited_flags(flags),

                              true, &local_err);

        if (ret < 0) {

            goto fail;

        }

    }



    /* Image format probing */

    bs->probed = !drv;

    if (!drv && file) {

        ret = find_image_format(file, filename, &drv, &local_err);

        if (ret < 0) {

            goto fail;

        }

    } else if (!drv) {

        error_setg(errp, "Must specify either driver or file");

        ret = -EINVAL;

        goto fail;

    }



    /* Open the image */

    ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);

    if (ret < 0) {

        goto fail;

    }



    if (file && (bs->file != file)) {

        bdrv_unref(file);

        file = NULL;

    }



    /* If there is a backing file, use it */

    if ((flags & BDRV_O_NO_BACKING) == 0) {

        QDict *backing_options;



        qdict_extract_subqdict(options, &backing_options, "backing.");

        ret = bdrv_open_backing_file(bs, backing_options, &local_err);

        if (ret < 0) {

            goto close_and_fail;

        }

    }



    bdrv_refresh_filename(bs);



    /* For snapshot=on, create a temporary qcow2 overlay. bs points to the

     * temporary snapshot afterwards. */

    if (snapshot_flags) {

        ret = bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err);

        if (local_err) {

            goto close_and_fail;

        }

    }



    /* Check if any unknown options were used */

    if (options && (qdict_size(options) != 0)) {

        const QDictEntry *entry = qdict_first(options);

        if (flags & BDRV_O_PROTOCOL) {

            error_setg(errp, "Block protocol '%s' doesn't support the option "

                       "'%s'", drv->format_name, entry->key);

        } else {

            error_setg(errp, "Block format '%s' used by device '%s' doesn't "

                       "support the option '%s'", drv->format_name,

                       bdrv_get_device_name(bs), entry->key);

        }



        ret = -EINVAL;

        goto close_and_fail;

    }



    if (!bdrv_key_required(bs)) {

        if (bs->blk) {

            blk_dev_change_media_cb(bs->blk, true);

        }

    } else if (!runstate_check(RUN_STATE_PRELAUNCH)

               && !runstate_check(RUN_STATE_INMIGRATE)

               && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */

        error_setg(errp,

                   "Guest must be stopped for opening of encrypted image");

        ret = -EBUSY;

        goto close_and_fail;

    }



    QDECREF(options);

    *pbs = bs;

    return 0;



fail:

    if (file != NULL) {

        bdrv_unref(file);

    }

    QDECREF(bs->options);

    QDECREF(options);

    bs->options = NULL;

    if (!*pbs) {

        /* If *pbs is NULL, a new BDS has been created in this function and

           needs to be freed now. Otherwise, it does not need to be closed,

           since it has not really been opened yet. */

        bdrv_unref(bs);

    }

    if (local_err) {

        error_propagate(errp, local_err);

    }

    return ret;



close_and_fail:

    /* See fail path, but now the BDS has to be always closed */

    if (*pbs) {

        bdrv_close(bs);

    } else {

        bdrv_unref(bs);

    }

    QDECREF(options);

    if (local_err) {

        error_propagate(errp, local_err);

    }

    return ret;

}

int bdrv_open(BlockDriverState **pbs, const char *filename,

              const char *reference, QDict *options, int flags,

              BlockDriver *drv, Error **errp)

{

    int ret;

    BlockDriverState *file = NULL, *bs;

    const char *drvname;

    Error *local_err = NULL;

    int snapshot_flags = 0;



    assert(pbs);



    if (reference) {

        bool options_non_empty = options ? qdict_size(options) : false;

        QDECREF(options);



        if (*pbs) {

            error_setg(errp, "Cannot reuse an existing BDS when referencing "

                       "another block device");

            return -EINVAL;

        }



        if (filename || options_non_empty) {

            error_setg(errp, "Cannot reference an existing block device with "

                       "additional options or a new filename");

            return -EINVAL;

        }



        bs = bdrv_lookup_bs(reference, reference, errp);

        if (!bs) {

            return -ENODEV;

        }

        bdrv_ref(bs);

        *pbs = bs;

        return 0;

    }



    if (*pbs) {

        bs = *pbs;

    } else {

        bs = bdrv_new();

    }



    

    if (options == NULL) {

        options = qdict_new();

    }



    ret = bdrv_fill_options(&options, &filename, flags, drv, &local_err);

    if (local_err) {

        goto fail;

    }



    

    drv = NULL;

    drvname = qdict_get_try_str(options, "driver");

    if (drvname) {

        drv = bdrv_find_format(drvname);

        qdict_del(options, "driver");

        if (!drv) {

            error_setg(errp, "Unknown driver: '%s'", drvname);

            ret = -EINVAL;

            goto fail;

        }

    }



    assert(drvname || !(flags & BDRV_O_PROTOCOL));

    if (drv && !drv->bdrv_file_open) {

        



        flags &= ~BDRV_O_PROTOCOL;

    }



    bs->options = options;

    options = qdict_clone_shallow(options);



    

    if ((flags & BDRV_O_PROTOCOL) == 0) {

        if (flags & BDRV_O_RDWR) {

            flags |= BDRV_O_ALLOW_RDWR;

        }

        if (flags & BDRV_O_SNAPSHOT) {

            snapshot_flags = bdrv_temp_snapshot_flags(flags);

            flags = bdrv_backing_flags(flags);

        }



        assert(file == NULL);

        ret = bdrv_open_image(&file, filename, options, "file",

                              bdrv_inherited_flags(flags),

                              true, &local_err);

        if (ret < 0) {

            goto fail;

        }

    }



    

    bs->probed = !drv;

    if (!drv && file) {

        ret = find_image_format(file, filename, &drv, &local_err);

        if (ret < 0) {

            goto fail;

        }

    } else if (!drv) {

        error_setg(errp, "Must specify either driver or file");

        ret = -EINVAL;

        goto fail;

    }



    

    ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);

    if (ret < 0) {

        goto fail;

    }



    if (file && (bs->file != file)) {

        bdrv_unref(file);

        file = NULL;

    }



    

    if ((flags & BDRV_O_NO_BACKING) == 0) {

        QDict *backing_options;



        qdict_extract_subqdict(options, &backing_options, "backing.");

        ret = bdrv_open_backing_file(bs, backing_options, &local_err);

        if (ret < 0) {

            goto close_and_fail;

        }

    }



    bdrv_refresh_filename(bs);



    



    if (snapshot_flags) {

        ret = bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err);

        if (local_err) {

            goto close_and_fail;

        }

    }



    

    if (options && (qdict_size(options) != 0)) {

        const QDictEntry *entry = qdict_first(options);

        if (flags & BDRV_O_PROTOCOL) {

            error_setg(errp, "Block protocol '%s' doesn't support the option "

                       "'%s'", drv->format_name, entry->key);

        } else {

            error_setg(errp, "Block format '%s' used by device '%s' doesn't "

                       "support the option '%s'", drv->format_name,

                       bdrv_get_device_name(bs), entry->key);

        }



        ret = -EINVAL;

        goto close_and_fail;

    }



    if (!bdrv_key_required(bs)) {

        if (bs->blk) {

            blk_dev_change_media_cb(bs->blk, true);

        }

    } else if (!runstate_check(RUN_STATE_PRELAUNCH)

               && !runstate_check(RUN_STATE_INMIGRATE)

               && !runstate_check(RUN_STATE_PAUSED)) { 

        error_setg(errp,

                   "Guest must be stopped for opening of encrypted image");

        ret = -EBUSY;

        goto close_and_fail;

    }



    QDECREF(options);

    *pbs = bs;

    return 0;



fail:

    if (file != NULL) {

        bdrv_unref(file);

    }

    QDECREF(bs->options);

    QDECREF(options);

    bs->options = NULL;

    if (!*pbs) {

        





        bdrv_unref(bs);

    }

    if (local_err) {

        error_propagate(errp, local_err);

    }

    return ret;



close_and_fail:

    

    if (*pbs) {

        bdrv_close(bs);

    } else {

        bdrv_unref(bs);

    }

    QDECREF(options);

    if (local_err) {

        error_propagate(errp, local_err);

    }

    return ret;

}

int FUNC_0(BlockDriverState **VAR_0, const char *VAR_1,

              const char *VAR_2, QDict *VAR_3, int VAR_4,

              BlockDriver *VAR_5, Error **VAR_6)

{

    int VAR_7;

    BlockDriverState *file = NULL, *bs;

    const char *VAR_8;

    Error *local_err = NULL;

    int VAR_9 = 0;



    assert(VAR_0);



    if (VAR_2) {

        bool options_non_empty = VAR_3 ? qdict_size(VAR_3) : false;

        QDECREF(VAR_3);



        if (*VAR_0) {

            error_setg(VAR_6, "Cannot reuse an existing BDS when referencing "

                       "another block device");

            return -EINVAL;

        }



        if (VAR_1 || options_non_empty) {

            error_setg(VAR_6, "Cannot VAR_2 an existing block device with "

                       "additional VAR_3 or a new VAR_1");

            return -EINVAL;

        }



        bs = bdrv_lookup_bs(VAR_2, VAR_2, VAR_6);

        if (!bs) {

            return -ENODEV;

        }

        bdrv_ref(bs);

        *VAR_0 = bs;

        return 0;

    }



    if (*VAR_0) {

        bs = *VAR_0;

    } else {

        bs = bdrv_new();

    }



    

    if (VAR_3 == NULL) {

        VAR_3 = qdict_new();

    }



    VAR_7 = bdrv_fill_options(&VAR_3, &VAR_1, VAR_4, VAR_5, &local_err);

    if (local_err) {

        goto fail;

    }



    

    VAR_5 = NULL;

    VAR_8 = qdict_get_try_str(VAR_3, "driver");

    if (VAR_8) {

        VAR_5 = bdrv_find_format(VAR_8);

        qdict_del(VAR_3, "driver");

        if (!VAR_5) {

            error_setg(VAR_6, "Unknown driver: '%s'", VAR_8);

            VAR_7 = -EINVAL;

            goto fail;

        }

    }



    assert(VAR_8 || !(VAR_4 & BDRV_O_PROTOCOL));

    if (VAR_5 && !VAR_5->bdrv_file_open) {

        



        VAR_4 &= ~BDRV_O_PROTOCOL;

    }



    bs->VAR_3 = VAR_3;

    VAR_3 = qdict_clone_shallow(VAR_3);



    

    if ((VAR_4 & BDRV_O_PROTOCOL) == 0) {

        if (VAR_4 & BDRV_O_RDWR) {

            VAR_4 |= BDRV_O_ALLOW_RDWR;

        }

        if (VAR_4 & BDRV_O_SNAPSHOT) {

            VAR_9 = bdrv_temp_snapshot_flags(VAR_4);

            VAR_4 = bdrv_backing_flags(VAR_4);

        }



        assert(file == NULL);

        VAR_7 = bdrv_open_image(&file, VAR_1, VAR_3, "file",

                              bdrv_inherited_flags(VAR_4),

                              true, &local_err);

        if (VAR_7 < 0) {

            goto fail;

        }

    }



    

    bs->probed = !VAR_5;

    if (!VAR_5 && file) {

        VAR_7 = find_image_format(file, VAR_1, &VAR_5, &local_err);

        if (VAR_7 < 0) {

            goto fail;

        }

    } else if (!VAR_5) {

        error_setg(VAR_6, "Must specify either driver or file");

        VAR_7 = -EINVAL;

        goto fail;

    }



    

    VAR_7 = bdrv_open_common(bs, file, VAR_3, VAR_4, VAR_5, &local_err);

    if (VAR_7 < 0) {

        goto fail;

    }



    if (file && (bs->file != file)) {

        bdrv_unref(file);

        file = NULL;

    }



    

    if ((VAR_4 & BDRV_O_NO_BACKING) == 0) {

        QDict *backing_options;



        qdict_extract_subqdict(VAR_3, &backing_options, "backing.");

        VAR_7 = bdrv_open_backing_file(bs, backing_options, &local_err);

        if (VAR_7 < 0) {

            goto close_and_fail;

        }

    }



    bdrv_refresh_filename(bs);



    



    if (VAR_9) {

        VAR_7 = bdrv_append_temp_snapshot(bs, VAR_9, &local_err);

        if (local_err) {

            goto close_and_fail;

        }

    }



    

    if (VAR_3 && (qdict_size(VAR_3) != 0)) {

        const QDictEntry *VAR_10 = qdict_first(VAR_3);

        if (VAR_4 & BDRV_O_PROTOCOL) {

            error_setg(VAR_6, "Block protocol '%s' doesn't support the option "

                       "'%s'", VAR_5->format_name, VAR_10->key);

        } else {

            error_setg(VAR_6, "Block format '%s' used by device '%s' doesn't "

                       "support the option '%s'", VAR_5->format_name,

                       bdrv_get_device_name(bs), VAR_10->key);

        }



        VAR_7 = -EINVAL;

        goto close_and_fail;

    }



    if (!bdrv_key_required(bs)) {

        if (bs->blk) {

            blk_dev_change_media_cb(bs->blk, true);

        }

    } else if (!runstate_check(RUN_STATE_PRELAUNCH)

               && !runstate_check(RUN_STATE_INMIGRATE)

               && !runstate_check(RUN_STATE_PAUSED)) { 

        error_setg(VAR_6,

                   "Guest must be stopped for opening of encrypted image");

        VAR_7 = -EBUSY;

        goto close_and_fail;

    }



    QDECREF(VAR_3);

    *VAR_0 = bs;

    return 0;



fail:

    if (file != NULL) {

        bdrv_unref(file);

    }

    QDECREF(bs->VAR_3);

    QDECREF(VAR_3);

    bs->VAR_3 = NULL;

    if (!*VAR_0) {

        





        bdrv_unref(bs);

    }

    if (local_err) {

        error_propagate(VAR_6, local_err);

    }

    return VAR_7;



close_and_fail:

    

    if (*VAR_0) {

        bdrv_close(bs);

    } else {

        bdrv_unref(bs);

    }

    QDECREF(VAR_3);

    if (local_err) {

        error_propagate(VAR_6, local_err);

    }

    return VAR_7;

}

int FUNC_0(BlockDriverState **VAR_0, const char *VAR_1,
const char *VAR_2, QDict *VAR_3, int VAR_4,
BlockDriver *VAR_5, Error **VAR_6)
{ int VAR_7; BlockDriverState *file = NULL, *bs; const char *VAR_8; Error *local_err = NULL; int VAR_9 = 0; assert(VAR_0); if (VAR_2) { bool options_non_empty = VAR_3 ? qdict_size(VAR_3) : false; QDECREF(VAR_3); if (*VAR_0) { error_setg(VAR_6, "Cannot reuse an existing BDS when referencing "
"another block device"); return -EINVAL; } if (VAR_1 || options_non_empty) { error_setg(VAR_6, "Cannot VAR_2 an existing block device with "
"additional VAR_3 or a new VAR_1"); return -EINVAL; } bs = bdrv_lookup_bs(VAR_2, VAR_2, VAR_6); if (!bs) { return -ENODEV; } bdrv_ref(bs); *VAR_0 = bs; return 0; } if (*VAR_0) { bs = *VAR_0; } else { bs = bdrv_new(); } if (VAR_3 == NULL) { VAR_3 = qdict_new(); } VAR_7 = bdrv_fill_options(&VAR_3, &VAR_1, VAR_4, VAR_5, &local_err); if (local_err) { goto fail; } VAR_5 = NULL; VAR_8 = qdict_get_try_str(VAR_3, "driver"); if (VAR_8) { VAR_5 = bdrv_find_format(VAR_8); qdict_del(VAR_3, "driver"); if (!VAR_5) { error_setg(VAR_6, "Unknown driver: '%s'", VAR_8); VAR_7 = -EINVAL; goto fail; } } assert(VAR_8 || !(VAR_4 & BDRV_O_PROTOCOL)); if (VAR_5 && !VAR_5->bdrv_file_open) { VAR_4 &= ~BDRV_O_PROTOCOL; } bs->VAR_3 = VAR_3; VAR_3 = qdict_clone_shallow(VAR_3); if ((VAR_4 & BDRV_O_PROTOCOL) == 0) { if (VAR_4 & BDRV_O_RDWR) { VAR_4 |= BDRV_O_ALLOW_RDWR; } if (VAR_4 & BDRV_O_SNAPSHOT) { VAR_9 = bdrv_temp_snapshot_flags(VAR_4); VAR_4 = bdrv_backing_flags(VAR_4); } assert(file == NULL); VAR_7 = bdrv_open_image(&file, VAR_1, VAR_3, "file",
bdrv_inherited_flags(VAR_4),
true, &local_err); if (VAR_7 < 0) { goto fail; } } bs->probed = !VAR_5; if (!VAR_5 && file) { VAR_7 = find_image_format(file, VAR_1, &VAR_5, &local_err); if (VAR_7 < 0) { goto fail; } } else if (!VAR_5) { error_setg(VAR_6, "Must specify either driver or file"); VAR_7 = -EINVAL; goto fail; } VAR_7 = bdrv_open_common(bs, file, VAR_3, VAR_4, VAR_5, &local_err); if (VAR_7 < 0) { goto fail; } if (file && (bs->file != file)) { bdrv_unref(file); file = NULL; } if ((VAR_4 & BDRV_O_NO_BACKING) == 0) { QDict *backing_options; qdict_extract_subqdict(VAR_3, &backing_options, "backing."); VAR_7 = bdrv_open_backing_file(bs, backing_options, &local_err); if (VAR_7 < 0) { goto close_and_fail; } } bdrv_refresh_filename(bs); if (VAR_9) { VAR_7 = bdrv_append_temp_snapshot(bs, VAR_9, &local_err); if (local_err) { goto close_and_fail; } } if (VAR_3 && (qdict_size(VAR_3) != 0)) { const QDictEntry *VAR_10 = qdict_first(VAR_3); if (VAR_4 & BDRV_O_PROTOCOL) { error_setg(VAR_6, "Block protocol '%s' doesn't support the option "
"'%s'", VAR_5->format_name, VAR_10->key); } else { error_setg(VAR_6, "Block format '%s' used by device '%s' doesn't "
"support the option '%s'", VAR_5->format_name,
bdrv_get_device_name(bs), VAR_10->key); } VAR_7 = -EINVAL; goto close_and_fail; } if (!bdrv_key_required(bs)) { if (bs->blk) { blk_dev_change_media_cb(bs->blk, true); } } else if (!runstate_check(RUN_STATE_PRELAUNCH) && !runstate_check(RUN_STATE_INMIGRATE)
&& !runstate_check(RUN_STATE_PAUSED)) { error_setg(VAR_6,
"Guest must be stopped for opening of encrypted image"); VAR_7 = -EBUSY; goto close_and_fail; } QDECREF(VAR_3); *VAR_0 = bs; return 0; fail:
if (file != NULL) { bdrv_unref(file); } QDECREF(bs->VAR_3); QDECREF(VAR_3); bs->VAR_3 = NULL; if (!*VAR_0) { bdrv_unref(bs); } if (local_err) { error_propagate(VAR_6, local_err); } return VAR_7; close_and_fail:
if (*VAR_0) { bdrv_close(bs); } else { bdrv_unref(bs); } QDECREF(VAR_3); if (local_err) { error_propagate(VAR_6, local_err); } return VAR_7; }