aboutsummaryrefslogtreecommitdiff
path: root/block/vmdk.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2012-09-09 16:21:39 +0300
committerAvi Kivity <avi@redhat.com>2012-09-09 16:21:39 +0300
commit3505aa6bec1a3bb474d81c495515b44654659a38 (patch)
treebf0f5f9e1a76159752047cdb239c62cbbd1f2ace /block/vmdk.c
parent7fa12eb15f95c269f488fce4096093c96dbaffab (diff)
parent4ce5bc2dd1914a706725186c6563e8f92eedfc84 (diff)
Merge tag 'v1.1.2' into stable-1.1qemu-kvm-1.1.2stable-1.1
* tag 'v1.1.2': (74 commits) update VERSION for 1.1.2 console: bounds check whenever changing the cursor due to an escape code qemu-timer: properly arm alarm timer for timers set by device initialization target-xtensa: return ENOSYS for unimplemented simcalls target-xtensa: fix big-endian BBS/BBC implementation ehci: Fix NULL ptr deref when unplugging an USB dev with an iso stream active msix: make [un]use vectors on reset/load optional reset PMBA and PMREGMISC PIIX4 registers. qemu_rearm_alarm_timer: do not call rearm if the next deadline is INT64_MAX qemu-ga: Fix null pointer passed to unlink in failure branch memory: Fix copy&paste mistake in memory_region_iorange_write ivshmem: remove redundant ioeventfd configuration hw/arm_gic.c: Define .class_size in arm_gic_info TypeInfo tcg/mips: fix broken CONFIG_TCG_PASS_AREG0 code audio/winwave: previous audio buffer should be flushed target-mips: allow microMIPS SWP and SDP to have RD equal to BASE target-mips: add privilege level check to several Cop0 instructions mips-linux-user: Always support rdhwr. target-mips: Streamline indexed cp1 memory addressing. Fix order of CVT.PS.S operands ... Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'block/vmdk.c')
-rw-r--r--block/vmdk.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/block/vmdk.c b/block/vmdk.c
index 18e9b4caf..a55f75652 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;
@@ -57,8 +58,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];
@@ -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) {