int bdrv_open(BlockDriverState *bs, const char *filename, int flags, BlockDriver *drv) { int ret; int probed = 0; if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; int64_t total_size; int is_protocol = 0; BlockDriver *bdrv_qcow2; QEMUOptionParameter *options; char tmp_filename[PATH_MAX]; char backing_filename[PATH_MAX]; /* if snapshot, we create a temporary backing file and open it instead of opening 'filename' directly */ /* if there is a backing file, use it */ bs1 = bdrv_new(""); ret = bdrv_open(bs1, filename, 0, drv); if (ret < 0) { bdrv_delete(bs1); return ret; } total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK; if (bs1->drv && bs1->drv->protocol_name) is_protocol = 1; bdrv_delete(bs1); get_tmp_filename(tmp_filename, sizeof(tmp_filename)); /* Real path is meaningless for protocols */ if (is_protocol) snprintf(backing_filename, sizeof(backing_filename), "%s", filename); else if (!realpath(filename, backing_filename)) return -errno; bdrv_qcow2 = bdrv_find_format("qcow2"); options = parse_option_parameters("", bdrv_qcow2->create_options, NULL); set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size); set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename); if (drv) { set_option_parameter(options, BLOCK_OPT_BACKING_FMT, drv->format_name); } ret = bdrv_create(bdrv_qcow2, tmp_filename, options); free_option_parameters(options); if (ret < 0) { return ret; } filename = tmp_filename; drv = bdrv_qcow2; bs->is_temporary = 1; } /* Find the right image format driver */ if (!drv) { drv = find_image_format(filename); probed = 1; } if (!drv) { ret = -ENOENT; goto unlink_and_fail; } /* Open the image */ ret = bdrv_open_common(bs, filename, flags, drv); if (ret < 0) { goto unlink_and_fail; } /* If there is a backing file, use it */ if ((flags & BDRV_O_NO_BACKING) == 0 && bs->backing_file[0] != '\0') { char backing_filename[PATH_MAX]; int back_flags; BlockDriver *back_drv = NULL; bs->backing_hd = bdrv_new(""); path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); if (bs->backing_format[0] != '\0') back_drv = bdrv_find_format(bs->backing_format); /* backing files always opened read-only */ back_flags = flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv); if (ret < 0) { bdrv_close(bs); return ret; } if (bs->is_temporary) { bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR); } else { /* base image inherits from "parent" */ bs->backing_hd->keep_read_only = bs->keep_read_only; } } if (!bdrv_key_required(bs)) { /* call the change callback */ bs->media_changed = 1; if (bs->change_cb) bs->change_cb(bs->change_opaque); } return 0; unlink_and_fail: if (bs->is_temporary) { unlink(filename); } return ret; }