diff options
author | Kevin Wolf <kwolf@redhat.com> | 2015-04-07 15:03:16 +0200 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2015-04-08 10:29:20 +0100 |
commit | e4603fe139e2161464d7e75faa3a650e31f057fc (patch) | |
tree | 7c0ccd7b76830684ed8a6f3a5f5219f2d542e700 /block/qcow2.c | |
parent | 5a24f20a7208a58fb80d78ca0521bba6f4d7b145 (diff) |
qcow2: Fix header update with overridden backing file
In recent qemu versions, it is possible to override the backing file
name and format that is stored in the image file with values given at
runtime. In such cases, the temporary override could end up in the
image header if the qcow2 header was updated, while obviously correct
behaviour would be to leave the on-disk backing file path/format
unchanged.
Fix this and add a test case for it.
Reported-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1428411796-2852-1-git-send-email-kwolf@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'block/qcow2.c')
-rw-r--r-- | block/qcow2.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/block/qcow2.c b/block/qcow2.c index 32bdf756ca..316a8db22b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -140,6 +140,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, return 3; } bs->backing_format[ext.len] = '\0'; + s->image_backing_format = g_strdup(bs->backing_format); #ifdef DEBUG_EXT printf("Qcow2: Got format extension %s\n", bs->backing_format); #endif @@ -884,6 +885,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } bs->backing_file[len] = '\0'; + s->image_backing_file = g_strdup(bs->backing_file); } /* Internal snapshots */ @@ -1457,6 +1459,9 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->unknown_header_fields); cleanup_unknown_header_ext(bs); + g_free(s->image_backing_file); + g_free(s->image_backing_format); + g_free(s->cluster_cache); qemu_vfree(s->cluster_data); qcow2_refcount_close(bs); @@ -1622,9 +1627,10 @@ int qcow2_update_header(BlockDriverState *bs) } /* Backing file format header extension */ - if (*bs->backing_format) { + if (s->image_backing_format) { ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BACKING_FORMAT, - bs->backing_format, strlen(bs->backing_format), + s->image_backing_format, + strlen(s->image_backing_format), buflen); if (ret < 0) { goto fail; @@ -1682,8 +1688,8 @@ int qcow2_update_header(BlockDriverState *bs) buflen -= ret; /* Backing file name */ - if (*bs->backing_file) { - size_t backing_file_len = strlen(bs->backing_file); + if (s->image_backing_file) { + size_t backing_file_len = strlen(s->image_backing_file); if (buflen < backing_file_len) { ret = -ENOSPC; @@ -1691,7 +1697,7 @@ int qcow2_update_header(BlockDriverState *bs) } /* Using strncpy is ok here, since buf is not NUL-terminated. */ - strncpy(buf, bs->backing_file, buflen); + strncpy(buf, s->image_backing_file, buflen); header->backing_file_offset = cpu_to_be64(buf - ((char*) header)); header->backing_file_size = cpu_to_be32(backing_file_len); @@ -1712,9 +1718,17 @@ fail: static int qcow2_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt) { + BDRVQcowState *s = bs->opaque; + pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: ""); pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: ""); + g_free(s->image_backing_file); + g_free(s->image_backing_format); + + s->image_backing_file = backing_file ? g_strdup(bs->backing_file) : NULL; + s->image_backing_format = backing_fmt ? g_strdup(bs->backing_format) : NULL; + return qcow2_update_header(bs); } @@ -2751,8 +2765,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } if (backing_file || backing_format) { - ret = qcow2_change_backing_file(bs, backing_file ?: bs->backing_file, - backing_format ?: bs->backing_format); + ret = qcow2_change_backing_file(bs, + backing_file ?: s->image_backing_file, + backing_format ?: s->image_backing_format); if (ret < 0) { return ret; } |