aboutsummaryrefslogtreecommitdiff
path: root/qemu-img.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu-img.c')
-rw-r--r--qemu-img.c50
1 files changed, 45 insertions, 5 deletions
diff --git a/qemu-img.c b/qemu-img.c
index 5bdac8ddb7..ceffefeacb 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -173,7 +173,8 @@ static void QEMU_NORETURN help(void)
"(default: 512)\n"
" 'count=N' copy only N input blocks\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);
bdrv_iterate_format(format_print, NULL);
@@ -3807,6 +3808,7 @@ out:
#define C_COUNT 02
#define C_IF 04
#define C_OF 010
+#define C_SKIP 020
struct DdInfo {
unsigned int flags;
@@ -3817,6 +3819,7 @@ struct DdIo {
int bsz; /* Block size */
char *filename;
uint8_t *buf;
+ int64_t offset;
};
struct DdOpts {
@@ -3877,6 +3880,22 @@ static int img_dd_of(const char *arg,
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)
{
int ret = 0;
@@ -3900,12 +3919,14 @@ static int img_dd(int argc, char **argv)
struct DdIo in = {
.bsz = 512, /* Block size is by default 512 bytes */
.filename = NULL,
- .buf = NULL
+ .buf = NULL,
+ .offset = 0
};
struct DdIo out = {
.bsz = 512,
.filename = NULL,
- .buf = NULL
+ .buf = NULL,
+ .offset = 0
};
const struct DdOpts options[] = {
@@ -3913,6 +3934,7 @@ static int img_dd(int argc, char **argv)
{ "count", img_dd_count, C_COUNT },
{ "if", img_dd_if, C_IF },
{ "of", img_dd_of, C_OF },
+ { "skip", img_dd_skip, C_SKIP },
{ NULL, NULL, 0 }
};
const struct option long_options[] = {
@@ -4032,7 +4054,14 @@ static int img_dd(int argc, char **argv)
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);
if (ret < 0) {
@@ -4051,9 +4080,20 @@ static int img_dd(int argc, char **argv)
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);
- 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;
if (in_pos + in.bsz > size) {