From patchwork Fri Aug 26 07:19:40 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reda Sallahi X-Patchwork-Id: 663001 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3sLCBb082Jz9sBR for ; Fri, 26 Aug 2016 17:20:53 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=oFp5nNHA; dkim-atps=neutral Received: from localhost ([::1]:59350 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bdBRa-0005rk-JE for incoming@patchwork.ozlabs.org; Fri, 26 Aug 2016 03:20:50 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34338) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bdBQr-0005SV-TX for qemu-devel@nongnu.org; Fri, 26 Aug 2016 03:20:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bdBQm-0007Kd-Q5 for qemu-devel@nongnu.org; Fri, 26 Aug 2016 03:20:04 -0400 Received: from mail-wm0-x243.google.com ([2a00:1450:400c:c09::243]:35781) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bdBQm-0007KK-FS; Fri, 26 Aug 2016 03:20:00 -0400 Received: by mail-wm0-x243.google.com with SMTP id i5so10205767wmg.2; Fri, 26 Aug 2016 00:19:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=Iy8RkIMyWV3QITBdVwEBnP6hwHdpOduzbkfHhX8b0c0=; b=oFp5nNHAFSpJJt6mGGq2CdFQdk13s01aBi1P3Jbxvalg/d213umd8QH33mET5rNB4C UoD+++FRV17wfgjc5UiG7ZfbEEMCpydQktmQBj1OMi0UWRORCHl2lwR8IWPH2VMDTGhx MLVGW0jJ7iaajeXPlow3oBlzlG1vvs2H9GaqsVjNmV+xYArbEyH0yJfDoNw+iii7QC7V qXEH/pioRDgD4ttLXYvCEADuzKanakDyZk38GO+5UOv6LoWLksjmeAVsoelifkK7snHc ziZQb1n0bCZgN5B+Q4HKjbj1yZG4IWbwAci/ZXitBNRpW5j5iuKtRI4wbvNSpO2OdOJh rORg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=Iy8RkIMyWV3QITBdVwEBnP6hwHdpOduzbkfHhX8b0c0=; b=FctWgPGVIGWmTBqC1u7WroYYf74sIbKQbCpuSfD4kKMudQvmQ2x+HC44HTs7sRBsIv 1Kio0L+rVf1dts2PLYMDoOH+CcBLIQJCBqSZ8W0hqFLHtTfeKjmQK3XOVzBLtuGjsMUk GKJuW8TKX2/P7tnMLxnynptXWQfBD60y0k5ylaepi60IAgOpg4n/2unvUPUUi7gpPvPs 65XFNv08MEYfpizUMtgUn1obJEHgYTmxqBV/xTvkgvTNrEZ6tdS1HCNLe6Hf9++FCJMj lcqVR02YUapoIVLlOJARw5IWTvQxmF/DgHL6XK3llUvkmeLvOyw2xxkrhui4GhTRyv8X p7hA== X-Gm-Message-State: AE9vXwMr3PCN9TJ2eiKgte4kcEyWboLdN0Cwsohqp+l/6AxGS4cWvZ8Wh1fz5P/2WhW8+A== X-Received: by 10.194.110.229 with SMTP id id5mr1958872wjb.23.1472195998356; Fri, 26 Aug 2016 00:19:58 -0700 (PDT) Received: from cinque_stelle.sm14.sm.cri.epita.net ([163.5.208.144]) by smtp.gmail.com with ESMTPSA id v203sm19229533wmv.2.2016.08.26.00.19.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 26 Aug 2016 00:19:56 -0700 (PDT) From: Reda Sallahi To: qemu-devel@nongnu.org Date: Fri, 26 Aug 2016 09:19:40 +0200 Message-Id: <20160826071940.1179-1-fullmanet@gmail.com> X-Mailer: git-send-email 2.9.3 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::243 Subject: [Qemu-devel] [PATCH v5] qemu-img: change opening method for the output in dd X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Max Reitz , Reda Sallahi , Stefan Hajnoczi Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The subcommand dd was creating an output image regardless of whether there was one already created. With this patch we try to check first if the output image exists and resize it if necessary. We also make it mandatory to specify conv=notrunc when the file already exists. Signed-off-by: Reda Sallahi --- Depends on: [PATCH v3] qemu-img: add conv=notrunc option to dd Changes from v4: * Use access() to check file existence first and remove blk_new_open() Changes from v3: * Remove unnecessary checks Changes from v2: * Remove redundant code Changes from v1: * add --image-opts handling qemu-img.c | 142 +++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 50 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index f8ba5e5..816a406 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3919,14 +3919,15 @@ static int img_dd(int argc, char **argv) char *tmp; BlockDriver *drv = NULL, *proto_drv = NULL; BlockBackend *blk1 = NULL, *blk2 = NULL; - QemuOpts *opts = NULL; + QemuOpts *opts = NULL, *qopts = NULL; QemuOptsList *create_opts = NULL; Error *local_err = NULL; bool image_opts = false; int c, i; const char *out_fmt = "raw"; const char *fmt = NULL; - int64_t size = 0; + const char *out_filename; + int64_t size = 0, out_size; int64_t block_count = 0, out_pos, in_pos; struct DdInfo dd = { .flags = 0, @@ -4030,36 +4031,6 @@ static int img_dd(int argc, char **argv) goto out; } - drv = bdrv_find_format(out_fmt); - if (!drv) { - error_report("Unknown file format"); - ret = -1; - goto out; - } - proto_drv = bdrv_find_protocol(out.filename, true, &local_err); - - if (!proto_drv) { - error_report_err(local_err); - ret = -1; - goto out; - } - if (!drv->create_opts) { - error_report("Format driver '%s' does not support image creation", - drv->format_name); - ret = -1; - goto out; - } - if (!proto_drv->create_opts) { - error_report("Protocol driver '%s' does not support image creation", - proto_drv->format_name); - ret = -1; - goto out; - } - create_opts = qemu_opts_append(create_opts, drv->create_opts); - create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); - - opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); - size = blk_getlength(blk1); if (size < 0) { error_report("Failed to get size for '%s'", in.filename); @@ -4071,31 +4042,101 @@ static int img_dd(int argc, char **argv) dd.count * in.bsz < size) { size = dd.count * in.bsz; } - /* Overflow means the specified offset is beyond input image's size */ - if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || - size < in.bsz * in.offset)) { - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort); + if (in.offset > INT64_MAX / in.bsz || size < in.offset * in.bsz) { + out_size = 0; } else { - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, - size - in.bsz * in.offset, &error_abort); + out_size = size - in.offset * in.bsz; } - ret = bdrv_create(drv, out.filename, opts, &local_err); - if (ret < 0) { - error_reportf_err(local_err, - "%s: error while creating output image: ", - out.filename); - ret = -1; - goto out; + out_filename = out.filename; + if (image_opts) { + qopts = qemu_opts_parse_noisily(qemu_find_opts("source"), + out.filename, true); + out_filename = qemu_opt_get(qopts, "filename"); } - blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR, - false, false); + ret = access(out_filename, F_OK); /* Check if file exists */ - if (!blk2) { - ret = -1; - goto out; + if (ret == -1) { + ret = 0; /* Reset */ + drv = bdrv_find_format(out_fmt); + if (!drv) { + error_report("Unknown file format"); + ret = -1; + goto out; + } + proto_drv = bdrv_find_protocol(out.filename, true, &local_err); + + if (!proto_drv) { + error_report_err(local_err); + ret = -1; + goto out; + } + if (!drv->create_opts) { + error_report("Format driver '%s' does not support image creation", + drv->format_name); + ret = -1; + goto out; + } + if (!proto_drv->create_opts) { + error_report("Protocol driver '%s' does not support image creation", + proto_drv->format_name); + ret = -1; + goto out; + } + create_opts = qemu_opts_append(create_opts, drv->create_opts); + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); + + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, out_size, &error_abort); + + ret = bdrv_create(drv, out.filename, opts, &local_err); + if (ret < 0) { + error_reportf_err(local_err, + "%s: error while creating output image: ", + out.filename); + ret = -1; + goto out; + } + blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR, + false, false); + if (!blk2) { + ret = -1; + goto out; + } + } else { + int64_t blk2sz = 0; + + blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR, + false, false); + if (!blk2) { + ret = -1; + goto out; + } + + if (!(dd.conv & C_NOTRUNC)) { + /* We make conv=notrunc mandatory for the moment to avoid + accidental destruction of the output image. Needs to be + changed when a better solution is found */ + error_report("conv=notrunc not specified"); + ret = -1; + goto out; + } + + blk2sz = blk_getlength(blk2); + if (blk2sz < 0) { + error_report("Failed to get size for '%s'", in.filename); + ret = -1; + goto out; + } + + if (in.offset <= INT64_MAX / in.bsz && size >= in.offset * in.bsz) { + if (blk2sz < out_size) { + blk_truncate(blk2, out_size); + } + } } if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || @@ -4141,6 +4182,7 @@ static int img_dd(int argc, char **argv) out: g_free(arg); qemu_opts_del(opts); + qemu_opts_del(qopts); qemu_opts_free(create_opts); blk_unref(blk1); blk_unref(blk2);