diff --git a/block/vmdk.c b/block/vmdk.c index 872aeba..4dfca58 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -43,19 +43,27 @@ typedef struct { uint32_t sectors_per_track; } VMDK3Header; +typedef uint8_t Bool; +typedef uint64_t SectorType; + typedef struct { uint32_t version; uint32_t flags; - int64_t capacity; - int64_t granularity; - int64_t desc_offset; - int64_t desc_size; - int32_t num_gtes_per_gte; - int64_t rgd_offset; - int64_t gd_offset; - int64_t grain_offset; - char filler[1]; - char check_bytes[4]; + SectorType capacity; + SectorType granularity; + SectorType desc_offset; + SectorType desc_size; + uint32_t num_gtes_per_gte; + SectorType rgd_offset; + SectorType gd_offset; + SectorType grain_offset; + Bool uncleanshutdown; + char singlendlinechar; + char nonendlinechar; + char doublendlinechar1; + char doublendlinechar2; + uint16_t compressAlgorithm; + uint8_t pad[433]; } __attribute__((packed)) VMDK4Header; #define L2_CACHE_SIZE 16 @@ -364,6 +372,10 @@ static int vmdk_open(BlockDriverState *bs, int flags) BDRVVmdkState *s = bs->opaque; uint32_t magic; int l1_size, i; + u_int64_t GD_AT_END = 0xffffffffffffffff; + struct stat sb; + uint32_t ret; + if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) goto fail; @@ -386,6 +398,19 @@ static int vmdk_open(BlockDriverState *bs, int flags) if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header)) goto fail; + if (le64_to_cpu(header.gd_offset) == GD_AT_END) { + uint64_t filesize; + if (stat(bs->filename, &sb) == -1) { + fprintf(stderr, "Unable to get file size.\n"); + return -1; + } + + filesize = (((uint64_t)sb.st_size + (512 - 1)) & ~(uint64_t)(512 - 1)); + ret = bdrv_pread(bs->file, (filesize - 1024 + sizeof(magic)), &header, sizeof(header)); + if (ret != sizeof(header)) { + return ret; + } + } bs->total_sectors = le64_to_cpu(header.capacity); s->cluster_sectors = le64_to_cpu(header.granularity); s->l2_size = le32_to_cpu(header.num_gtes_per_gte); @@ -395,8 +420,7 @@ static int vmdk_open(BlockDriverState *bs, int flags) s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1) / s->l1_entry_sectors; s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9; - s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9; - + s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9; // try to open parent images, if exist if (vmdk_parent_open(bs) != 0) goto fail; @@ -424,6 +448,7 @@ static int vmdk_open(BlockDriverState *bs, int flags) } } + s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t)); return 0; fail: @@ -743,11 +768,11 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) header.gd_offset = cpu_to_le64(header.gd_offset); header.grain_offset = cpu_to_le64(header.grain_offset); - header.check_bytes[0] = 0xa; + /* header.check_bytes[0] = 0xa; header.check_bytes[1] = 0x20; header.check_bytes[2] = 0xd; header.check_bytes[3] = 0xa; - + */ /* write all the data */ ret = qemu_write_full(fd, &magic, sizeof(magic)); if (ret != sizeof(magic)) {