aboutsummaryrefslogtreecommitdiff
path: root/block-vpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'block-vpc.c')
-rw-r--r--block-vpc.c118
1 files changed, 82 insertions, 36 deletions
diff --git a/block-vpc.c b/block-vpc.c
index 0b4666d..3f25785 100644
--- a/block-vpc.c
+++ b/block-vpc.c
@@ -30,41 +30,87 @@
//#define CACHE
+enum vhd_type {
+ VHD_FIXED = 2,
+ VHD_DYNAMIC = 3,
+ VHD_DIFFERENCING = 4,
+};
+
// always big-endian
struct vhd_footer {
- char creator[8]; // "conectix
- uint32_t unk1[2];
- uint32_t unk2; // always zero?
- uint32_t subheader_offset;
- uint32_t unk3; // some size?
- char creator_app[4]; // "vpc "
- uint16_t major;
- uint16_t minor;
- char guest[4]; // "Wi2k"
- uint32_t unk4[7];
- uint8_t vnet_id[16]; // virtual network id, purpose unknown
- // next 16 longs are used, but dunno the purpose
- // next 6 longs unknown, following 7 long maybe a serial
+ char creator[8]; // "conectix"
+ uint32_t features;
+ uint32_t version;
+
+ // Offset of next header structure, 0xFFFFFFFF if none
+ uint64_t data_offset;
+
+ // Seconds since Jan 1, 2000 0:00:00 (UTC)
+ uint32_t timestamp;
+
+ char creator_app[4]; // "vpc "
+ uint16_t major;
+ uint16_t minor;
+ char creator_os[4]; // "Wi2k"
+
+ uint64_t orig_size;
+ uint64_t size;
+
+ uint16_t cyls;
+ uint8_t heads;
+ uint8_t secs_per_cyl;
+
+ uint32_t type;
+
+ // Checksum of the Hard Disk Footer ("one's complement of the sum of all
+ // the bytes in the footer without the checksum field")
+ uint32_t checksum;
+
+ // UUID used to identify a parent hard disk (backing file)
+ uint8_t uuid[16];
+
+ uint8_t in_saved_state;
};
struct vhd_dyndisk_header {
- char magic[8]; // "cxsparse"
- uint32_t unk1[2]; // all bits set
- uint32_t unk2; // always zero?
- uint32_t pagetable_offset;
- uint32_t unk3;
- uint32_t pagetable_entries; // 32bit/entry
- uint32_t pageentry_size; // 512*8*512
- uint32_t nb_sectors;
+ char magic[8]; // "cxsparse"
+
+ // Offset of next header structure, 0xFFFFFFFF if none
+ uint64_t data_offset;
+
+ // Offset of the Block Allocation Table (BAT)
+ uint64_t table_offset;
+
+ uint32_t version;
+ uint32_t max_table_entries; // 32bit/entry
+
+ // 2 MB by default, must be a power of two
+ uint32_t block_size;
+
+ uint32_t checksum;
+ uint8_t parent_uuid[16];
+ uint32_t parent_timestamp;
+ uint32_t reserved;
+
+ // Backing file name (in UTF-16)
+ uint8_t parent_name[512];
+
+ struct {
+ uint32_t platform;
+ uint32_t data_space;
+ uint32_t data_length;
+ uint32_t reserved;
+ uint64_t data_offset;
+ } parent_locator[8];
};
typedef struct BDRVVPCState {
int fd;
- int pagetable_entries;
+ int max_table_entries;
uint32_t *pagetable;
- uint32_t pageentry_size;
+ uint32_t block_size;
#ifdef CACHE
uint8_t *pageentry_u8;
uint32_t *pageentry_u32;
@@ -104,7 +150,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
if (strncmp(footer->creator, "conectix", 8))
goto fail;
- lseek(s->fd, be32_to_cpu(footer->subheader_offset), SEEK_SET);
+ lseek(s->fd, be64_to_cpu(footer->data_offset), SEEK_SET);
if (read(fd, buf, HEADER_SIZE) != HEADER_SIZE)
goto fail;
@@ -114,22 +160,22 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
if (strncmp(dyndisk_header->magic, "cxsparse", 8))
goto fail;
- bs->total_sectors = ((uint64_t)be32_to_cpu(dyndisk_header->pagetable_entries) *
- be32_to_cpu(dyndisk_header->pageentry_size)) / 512;
+ bs->total_sectors = ((uint64_t)be32_to_cpu(dyndisk_header->max_table_entries) *
+ be32_to_cpu(dyndisk_header->block_size)) / 512;
- lseek(s->fd, be32_to_cpu(dyndisk_header->pagetable_offset), SEEK_SET);
+ lseek(s->fd, be64_to_cpu(dyndisk_header->table_offset), SEEK_SET);
- s->pagetable_entries = be32_to_cpu(dyndisk_header->pagetable_entries);
- s->pagetable = qemu_malloc(s->pagetable_entries * 4);
+ s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
+ s->pagetable = qemu_malloc(s->max_table_entries * 4);
if (!s->pagetable)
goto fail;
- if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
- s->pagetable_entries * 4)
+ if (read(s->fd, s->pagetable, s->max_table_entries * 4) !=
+ s->max_table_entries * 4)
goto fail;
- for (i = 0; i < s->pagetable_entries; i++)
+ for (i = 0; i < s->max_table_entries; i++)
be32_to_cpus(&s->pagetable[i]);
- s->pageentry_size = be32_to_cpu(dyndisk_header->pageentry_size);
+ s->block_size = be32_to_cpu(dyndisk_header->block_size);
#ifdef CACHE
s->pageentry_u8 = qemu_malloc(512);
if (!s->pageentry_u8)
@@ -152,10 +198,10 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, pageentry_index;
- pagetable_index = offset / s->pageentry_size;
- pageentry_index = (offset % s->pageentry_size) / 512;
+ pagetable_index = offset / s->block_size;
+ pageentry_index = (offset % s->block_size) / 512;
- if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
+ if (pagetable_index > s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
return -1; // not allocated
bitmap_offset = 512 * s->pagetable[pagetable_index];