qemu-img: add skip option to dd

This adds the skip option which allows qemu-img dd to skip a number of blocks
before copying the input.

A test case was added to test the skip option.

Signed-off-by: Reda Sallahi <fullmanet@gmail.com>
Message-id: 20160810141609.32727-1-fullmanet@gmail.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Reda Sallahi 2016-08-10 16:16:09 +02:00 committed by Max Reitz
parent 86ce1f6e2b
commit f7c1553388
6 changed files with 174 additions and 8 deletions

View File

@ -46,9 +46,9 @@ STEXI
ETEXI ETEXI
DEF("dd", img_dd, DEF("dd", img_dd,
"dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] if=input of=output") "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output")
STEXI STEXI
@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] if=@var{input} of=@var{output} @item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output}
ETEXI ETEXI
DEF("info", img_info, DEF("info", img_info,

View File

@ -173,7 +173,8 @@ static void QEMU_NORETURN help(void)
"(default: 512)\n" "(default: 512)\n"
" 'count=N' copy only N input blocks\n" " 'count=N' copy only N input blocks\n"
" 'if=FILE' read from FILE\n" " 'if=FILE' read from FILE\n"
" 'of=FILE' write to FILE\n"; " 'of=FILE' write to FILE\n"
" 'skip=N' skip N bs-sized blocks at the start of input\n";
printf("%s\nSupported formats:", help_msg); printf("%s\nSupported formats:", help_msg);
bdrv_iterate_format(format_print, NULL); bdrv_iterate_format(format_print, NULL);
@ -3807,6 +3808,7 @@ out:
#define C_COUNT 02 #define C_COUNT 02
#define C_IF 04 #define C_IF 04
#define C_OF 010 #define C_OF 010
#define C_SKIP 020
struct DdInfo { struct DdInfo {
unsigned int flags; unsigned int flags;
@ -3817,6 +3819,7 @@ struct DdIo {
int bsz; /* Block size */ int bsz; /* Block size */
char *filename; char *filename;
uint8_t *buf; uint8_t *buf;
int64_t offset;
}; };
struct DdOpts { struct DdOpts {
@ -3877,6 +3880,22 @@ static int img_dd_of(const char *arg,
return 0; return 0;
} }
static int img_dd_skip(const char *arg,
struct DdIo *in, struct DdIo *out,
struct DdInfo *dd)
{
char *end;
in->offset = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
if (in->offset < 0 || *end) {
error_report("invalid number: '%s'", arg);
return 1;
}
return 0;
}
static int img_dd(int argc, char **argv) static int img_dd(int argc, char **argv)
{ {
int ret = 0; int ret = 0;
@ -3900,12 +3919,14 @@ static int img_dd(int argc, char **argv)
struct DdIo in = { struct DdIo in = {
.bsz = 512, /* Block size is by default 512 bytes */ .bsz = 512, /* Block size is by default 512 bytes */
.filename = NULL, .filename = NULL,
.buf = NULL .buf = NULL,
.offset = 0
}; };
struct DdIo out = { struct DdIo out = {
.bsz = 512, .bsz = 512,
.filename = NULL, .filename = NULL,
.buf = NULL .buf = NULL,
.offset = 0
}; };
const struct DdOpts options[] = { const struct DdOpts options[] = {
@ -3913,6 +3934,7 @@ static int img_dd(int argc, char **argv)
{ "count", img_dd_count, C_COUNT }, { "count", img_dd_count, C_COUNT },
{ "if", img_dd_if, C_IF }, { "if", img_dd_if, C_IF },
{ "of", img_dd_of, C_OF }, { "of", img_dd_of, C_OF },
{ "skip", img_dd_skip, C_SKIP },
{ NULL, NULL, 0 } { NULL, NULL, 0 }
}; };
const struct option long_options[] = { const struct option long_options[] = {
@ -4032,7 +4054,14 @@ static int img_dd(int argc, char **argv)
size = dd.count * in.bsz; size = dd.count * in.bsz;
} }
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort); /* 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);
} else {
qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
size - in.bsz * in.offset, &error_abort);
}
ret = bdrv_create(drv, out.filename, opts, &local_err); ret = bdrv_create(drv, out.filename, opts, &local_err);
if (ret < 0) { if (ret < 0) {
@ -4051,9 +4080,20 @@ static int img_dd(int argc, char **argv)
goto out; goto out;
} }
if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
size < in.offset * in.bsz)) {
/* We give a warning if the skip option is bigger than the input
* size and create an empty output disk image (i.e. like dd(1)).
*/
error_report("%s: cannot skip to specified offset", in.filename);
in_pos = size;
} else {
in_pos = in.offset * in.bsz;
}
in.buf = g_new(uint8_t, in.bsz); in.buf = g_new(uint8_t, in.bsz);
for (in_pos = 0, out_pos = 0; in_pos < size; block_count++) { for (out_pos = 0; in_pos < size; block_count++) {
int in_ret, out_ret; int in_ret, out_ret;
if (in_pos + in.bsz > size) { if (in_pos + in.bsz > size) {

View File

@ -151,6 +151,8 @@ sets the number of input blocks to copy
sets the input file sets the input file
@item of=@var{output} @item of=@var{output}
sets the output file sets the output file
@item skip=@var{blocks}
sets the number of input blocks to skip
@end table @end table
Command description: Command description:
@ -324,7 +326,7 @@ skipped. This is useful for formats such as @code{rbd} if the target
volume has already been created with site specific options that cannot volume has already been created with site specific options that cannot
be supplied through qemu-img. be supplied through qemu-img.
@item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] if=@var{input} of=@var{output} @item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output}
Dd copies from @var{input} file to @var{output} file converting it from Dd copies from @var{input} file to @var{output} file converting it from
@var{fmt} format to @var{output_fmt} format. @var{fmt} format to @var{output_fmt} format.

72
tests/qemu-iotests/160 Executable file
View File

@ -0,0 +1,72 @@
#! /bin/bash
#
# qemu-img dd test for the skip option
#
# Copyright (C) 2016 Reda Sallahi
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
owner=fullmanet@gmail.com
seq="$(basename $0)"
echo "QA output created by $seq"
here="$PWD"
status=1
_cleanup()
{
_cleanup_test_img
rm -f "$TEST_IMG.out" "$TEST_IMG.out.dd"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
. ./common.pattern
_supported_fmt raw
_supported_proto file
_supported_os Linux
TEST_SKIP_BLOCKS="1 2 30 30K"
for skip in $TEST_SKIP_BLOCKS; do
echo
echo "== Creating image =="
size=1M
_make_test_img $size
_check_test_img
$QEMU_IO -c "write -P 0xa 24 512k" "$TEST_IMG" | _filter_qemu_io
echo
echo "== Converting the image with dd with skip=$skip =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" skip="$skip" -O "$IMGFMT" \
2> /dev/null
TEST_IMG="$TEST_IMG.out" _check_test_img
dd if="$TEST_IMG" of="$TEST_IMG.out.dd" skip="$skip" status=none
echo
echo "== Compare the images with qemu-img compare =="
$QEMU_IMG compare "$TEST_IMG.out.dd" "$TEST_IMG.out"
done
echo
echo "*** done"
rm -f "$seq.full"
status=0

View File

@ -0,0 +1,51 @@
QA output created by 160
== Creating image ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
No errors were found on the image.
wrote 524288/524288 bytes at offset 24
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== Converting the image with dd with skip=1 ==
No errors were found on the image.
== Compare the images with qemu-img compare ==
Images are identical.
== Creating image ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
No errors were found on the image.
wrote 524288/524288 bytes at offset 24
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== Converting the image with dd with skip=2 ==
No errors were found on the image.
== Compare the images with qemu-img compare ==
Images are identical.
== Creating image ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
No errors were found on the image.
wrote 524288/524288 bytes at offset 24
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== Converting the image with dd with skip=30 ==
No errors were found on the image.
== Compare the images with qemu-img compare ==
Images are identical.
== Creating image ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
No errors were found on the image.
wrote 524288/524288 bytes at offset 24
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== Converting the image with dd with skip=30K ==
No errors were found on the image.
== Compare the images with qemu-img compare ==
Images are identical.
*** done

View File

@ -158,5 +158,6 @@
156 rw auto quick 156 rw auto quick
157 auto 157 auto
159 rw auto quick 159 rw auto quick
160 rw auto quick
162 auto quick 162 auto quick
170 rw auto quick 170 rw auto quick