From 7a736bfa4e0a58087054cad68a1d4b3804bbb708 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 16 Aug 2012 10:34:10 +0200 Subject: vmdk: Fix header structure Commit bb45ded9 swapped gd_offset and rgd_offset. This is wrong. Signed-off-by: Kevin Wolf --- block/vmdk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'block') diff --git a/block/vmdk.c b/block/vmdk.c index daee4268be..9648398822 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -57,8 +57,8 @@ typedef struct { int64_t desc_offset; int64_t desc_size; int32_t num_gtes_per_gte; - int64_t gd_offset; int64_t rgd_offset; + int64_t gd_offset; int64_t grain_offset; char filler[1]; char check_bytes[4]; -- cgit v1.2.3 From 65bd155c7356d448ffee7f89149c4d473076b0ba Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 16 Aug 2012 10:39:33 +0200 Subject: vmdk: Read footer for streamOptimized images The footer takes precedence over the header when it exists. It contains the real grain directory offset that is missing in the header. Without this patch, streamOptimized images with a footer cannot be read. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi Reviewed-by: Jeff Cody --- block/vmdk.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'block') diff --git a/block/vmdk.c b/block/vmdk.c index 9648398822..bba4c61a74 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -35,6 +35,7 @@ #define VMDK4_FLAG_RGD (1 << 1) #define VMDK4_FLAG_COMPRESS (1 << 16) #define VMDK4_FLAG_MARKER (1 << 17) +#define VMDK4_GD_AT_END 0xffffffffffffffffULL typedef struct { uint32_t version; @@ -115,6 +116,13 @@ typedef struct VmdkGrainMarker { uint8_t data[0]; } VmdkGrainMarker; +enum { + MARKER_END_OF_STREAM = 0, + MARKER_GRAIN_TABLE = 1, + MARKER_GRAIN_DIRECTORY = 2, + MARKER_FOOTER = 3, +}; + static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) { uint32_t magic; @@ -451,6 +459,54 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, if (header.capacity == 0 && header.desc_offset) { return vmdk_open_desc_file(bs, flags, header.desc_offset << 9); } + + if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) { + /* + * The footer takes precedence over the header, so read it in. The + * footer starts at offset -1024 from the end: One sector for the + * footer, and another one for the end-of-stream marker. + */ + struct { + struct { + uint64_t val; + uint32_t size; + uint32_t type; + uint8_t pad[512 - 16]; + } QEMU_PACKED footer_marker; + + uint32_t magic; + VMDK4Header header; + uint8_t pad[512 - 4 - sizeof(VMDK4Header)]; + + struct { + uint64_t val; + uint32_t size; + uint32_t type; + uint8_t pad[512 - 16]; + } QEMU_PACKED eos_marker; + } QEMU_PACKED footer; + + ret = bdrv_pread(file, + bs->file->total_sectors * 512 - 1536, + &footer, sizeof(footer)); + if (ret < 0) { + return ret; + } + + /* Some sanity checks for the footer */ + if (be32_to_cpu(footer.magic) != VMDK4_MAGIC || + le32_to_cpu(footer.footer_marker.size) != 0 || + le32_to_cpu(footer.footer_marker.type) != MARKER_FOOTER || + le64_to_cpu(footer.eos_marker.val) != 0 || + le32_to_cpu(footer.eos_marker.size) != 0 || + le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM) + { + return -EINVAL; + } + + header = footer.header; + } + l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte) * le64_to_cpu(header.granularity); if (l1_entry_sectors == 0) { -- cgit v1.2.3