diff --git a/block.c b/block.c index 217f523dd08796ce9bef0ce92da45ec66c00bd58..757d139a1f83d36744061d60437b0395495f044e 100644 --- a/block.c +++ b/block.c @@ -1006,77 +1006,103 @@ free_and_fail: } /* - * Opens a file using a protocol (file, host_device, nbd, ...) - * - * options is an indirect pointer to a QDict of options to pass to the block - * drivers, or pointer to NULL for an empty set of options. If this function - * takes ownership of the QDict reference, it will set *options to NULL; - * otherwise, it will contain unused/unrecognized options after this function - * returns. Then, the caller is responsible for freeing it. If it intends to - * reuse the QDict, QINCREF() should be called beforehand. + * Fills in default options for opening images and converts the legacy + * filename/flags pair to option QDict entries. */ -static int bdrv_file_open(BlockDriverState *bs, const char *filename, - QDict **options, int flags, Error **errp) +static int bdrv_fill_options(QDict **options, const char *filename, + Error **errp) { - BlockDriver *drv; const char *drvname; bool parse_filename = false; Error *local_err = NULL; - int ret; + BlockDriver *drv; /* Fetch the file name from the options QDict if necessary */ - if (!filename) { - filename = qdict_get_try_str(*options, "filename"); - } else if (filename && !qdict_haskey(*options, "filename")) { - qdict_put(*options, "filename", qstring_from_str(filename)); - parse_filename = true; - } else { - error_setg(errp, "Can't specify 'file' and 'filename' options at the " - "same time"); - ret = -EINVAL; - goto fail; + if (filename) { + if (!qdict_haskey(*options, "filename")) { + qdict_put(*options, "filename", qstring_from_str(filename)); + parse_filename = true; + } else { + error_setg(errp, "Can't specify 'file' and 'filename' options at " + "the same time"); + return -EINVAL; + } } /* Find the right block driver */ + filename = qdict_get_try_str(*options, "filename"); drvname = qdict_get_try_str(*options, "driver"); - if (drvname) { - drv = bdrv_find_format(drvname); - if (!drv) { - error_setg(errp, "Unknown driver '%s'", drvname); - } - qdict_del(*options, "driver"); - } else if (filename) { - drv = bdrv_find_protocol(filename, parse_filename); - if (!drv) { - error_setg(errp, "Unknown protocol"); + + if (!drvname) { + if (filename) { + drv = bdrv_find_protocol(filename, parse_filename); + if (!drv) { + error_setg(errp, "Unknown protocol"); + return -EINVAL; + } + + drvname = drv->format_name; + qdict_put(*options, "driver", qstring_from_str(drvname)); + } else { + error_setg(errp, "Must specify either driver or file"); + return -EINVAL; } - } else { - error_setg(errp, "Must specify either driver or file"); - drv = NULL; } + drv = bdrv_find_format(drvname); if (!drv) { - /* errp has been set already */ - ret = -ENOENT; - goto fail; + error_setg(errp, "Unknown driver '%s'", drvname); + return -ENOENT; } - /* Parse the filename and open it */ + /* Driver-specific filename parsing */ if (drv->bdrv_parse_filename && parse_filename) { drv->bdrv_parse_filename(filename, *options, &local_err); if (local_err) { error_propagate(errp, local_err); - ret = -EINVAL; - goto fail; + return -EINVAL; } if (!drv->bdrv_needs_filename) { qdict_del(*options, "filename"); - } else { - filename = qdict_get_str(*options, "filename"); } } + return 0; +} + +/* + * Opens a file using a protocol (file, host_device, nbd, ...) + * + * options is an indirect pointer to a QDict of options to pass to the block + * drivers, or pointer to NULL for an empty set of options. If this function + * takes ownership of the QDict reference, it will set *options to NULL; + * otherwise, it will contain unused/unrecognized options after this function + * returns. Then, the caller is responsible for freeing it. If it intends to + * reuse the QDict, QINCREF() should be called beforehand. + */ +static int bdrv_file_open(BlockDriverState *bs, const char *filename, + QDict **options, int flags, Error **errp) +{ + BlockDriver *drv; + const char *drvname; + Error *local_err = NULL; + int ret; + + ret = bdrv_fill_options(options, filename, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto fail; + } + + filename = qdict_get_try_str(*options, "filename"); + drvname = qdict_get_str(*options, "driver"); + + drv = bdrv_find_format(drvname); + assert(drv); + qdict_del(*options, "driver"); + + /* Open the file */ if (!drv->bdrv_file_open) { ret = bdrv_open(&bs, filename, NULL, *options, flags, drv, &local_err); *options = NULL;