private void GetRegions(out VHDX_REGION_TABLE_ENTRY outBatRegion, out VHDX_REGION_TABLE_ENTRY outMetadataRegion) { UInt64 sig; mHdd.Get(0, out sig); if (sig != VHDX_SIG) { throw new Exception("VHDX sig missing!"); } var headers = new List <VHDX_HEADER>(); MaybeGetHeader(headers, HEADER_SIZE); MaybeGetHeader(headers, 2 * HEADER_SIZE); var head = headers.OrderByDescending(h => h.SequenceNumber).First(); if (head.Version != 1) { throw new NotSupportedException($"Unsupported VHDX version: {head.Version}"); } if (head.LogGuid != Guid.Empty) { throw new NotImplementedException("Processing log entries is not supported."); } //I'm assuming that both region tables are the same, so I just read the first one. var regionTableBytes = mHdd.ReadBytes(HEADER_SIZE * 3, HEADER_SIZE); var regionTable = Program.ToStruct <VHDX_REGION_TABLE_HEADER>(regionTableBytes); if (regionTable.Signature != REGION_TABLE_SIG) { throw new Exception("Signature of region table is wrong!"); } for (int i = 0; i < 4; i++) { regionTableBytes[i + 4] = 0; } if (regionTable.Checksum != Crc32Algorithm.Compute(regionTableBytes)) { throw new Exception("Bad region table checksum!"); } if (regionTable.EntryCount > 2047) { throw new Exception("Too many region table entries!"); } VHDX_REGION_TABLE_ENTRY?batRegion = null, metadataRegion = null; for (int i = 0; i < regionTable.EntryCount; i++) { int offset = Program.SizeOf <VHDX_REGION_TABLE_HEADER>() + i * Program.SizeOf <VHDX_REGION_TABLE_ENTRY>(); var entry = Program.ToStruct <VHDX_REGION_TABLE_ENTRY>(regionTableBytes, offset); if (entry.Guid == REGION_BAT) { batRegion = entry; } else if (entry.Guid == REGION_METADATA) { metadataRegion = entry; } else if (entry.Required) { throw new Exception($"Unknown region: {entry.Guid}"); } } if (!batRegion.HasValue) { throw new Exception("Could not find BAT region!"); } if (!metadataRegion.HasValue) { throw new Exception("Could not find metadata region!"); } outBatRegion = batRegion.Value; outMetadataRegion = metadataRegion.Value; }
private void ReadMetadata(VHDX_REGION_TABLE_ENTRY metadataRegion, out VHDX_FILE_PARAMETERS outFileParams, out Int64 outVirtualDiskSize, out uint outLogicalSectorSize) { if (metadataRegion.Length < METADATA_TABLE_SIZE) throw new Exception("Metadata region is too small to contain metadata table!"); var metadataBytes = mHdd.ReadBytes(checked((long)metadataRegion.FileOffset), checked((int)metadataRegion.Length)); var metadataHeader = Program.ToStruct<VHDX_METADATA_TABLE_HEADER>(metadataBytes, 0); if (metadataHeader.Signature != METADATA_TABLE_SIG) throw new Exception("Bad metadata header sig."); if (metadataHeader.EntryCount > MAX_TABLE_ENTRIES) throw new Exception("Too many metadata entries."); VHDX_FILE_PARAMETERS? fileParams = null; UInt64? virtualDiskSize = null; UInt32? logicalSectorSize = null; for (int i = 0; i < metadataHeader.EntryCount; i++) { int readOffset = Program.SizeOf<VHDX_METADATA_TABLE_HEADER>() + i * Program.SizeOf<VHDX_METADATA_TABLE_ENTRY>(); var entry = Program.ToStruct<VHDX_METADATA_TABLE_ENTRY>(metadataBytes, readOffset); if (entry.IsUser) { if (entry.IsRequired) throw new Exception($"Unknown required metadata item: {entry.ItemId}"); else continue; } else if (entry.IsRequired && !sKnownMetadataItems.Contains(entry.ItemId)) throw new Exception($"Unknown required metadata item: {entry.ItemId}"); //the ArraySegment overload of ToStruct will make sure the entry size matches the data item var entryBytes = new ArraySegment<byte>(metadataBytes, checked((int)entry.Offset), checked((int)entry.Length)); if (entry.ItemId == METADATA_FILE_PARAMS) { fileParams = Program.ToStruct<VHDX_FILE_PARAMETERS>(entryBytes); } else if (entry.ItemId == METADATA_VIRTUAL_DISK_SIZE) { virtualDiskSize = Program.ToStruct<UInt64>(entryBytes); } else if (entry.ItemId == METADATA_LOGICAL_SECTOR_SIZE) { logicalSectorSize = Program.ToStruct<UInt32>(entryBytes); } } if (!fileParams.HasValue || !virtualDiskSize.HasValue || !logicalSectorSize.HasValue) throw new Exception("Missing required metadata!"); outFileParams = fileParams.Value; outVirtualDiskSize = checked((long)virtualDiskSize.Value); outLogicalSectorSize = logicalSectorSize.Value; }
private void ReadMetadata(VHDX_REGION_TABLE_ENTRY metadataRegion, out VHDX_FILE_PARAMETERS outFileParams, out Int64 outVirtualDiskSize, out uint outLogicalSectorSize) { if (metadataRegion.Length < METADATA_TABLE_SIZE) { throw new Exception("Metadata region is too small to contain metadata table!"); } var metadataBytes = mHdd.ReadBytes(checked ((long)metadataRegion.FileOffset), checked ((int)metadataRegion.Length)); var metadataHeader = Program.ToStruct <VHDX_METADATA_TABLE_HEADER>(metadataBytes, 0); if (metadataHeader.Signature != METADATA_TABLE_SIG) { throw new Exception("Bad metadata header sig."); } if (metadataHeader.EntryCount > MAX_TABLE_ENTRIES) { throw new Exception("Too many metadata entries."); } VHDX_FILE_PARAMETERS?fileParams = null; UInt64?virtualDiskSize = null; UInt32?logicalSectorSize = null; for (int i = 0; i < metadataHeader.EntryCount; i++) { int readOffset = Program.SizeOf <VHDX_METADATA_TABLE_HEADER>() + i * Program.SizeOf <VHDX_METADATA_TABLE_ENTRY>(); var entry = Program.ToStruct <VHDX_METADATA_TABLE_ENTRY>(metadataBytes, readOffset); if (entry.IsUser) { if (entry.IsRequired) { throw new Exception($"Unknown required metadata item: {entry.ItemId}"); } else { continue; } } else if (entry.IsRequired && !sKnownMetadataItems.Contains(entry.ItemId)) { throw new Exception($"Unknown required metadata item: {entry.ItemId}"); } //the ArraySegment overload of ToStruct will make sure the entry size matches the data item var entryBytes = new ArraySegment <byte>(metadataBytes, checked ((int)entry.Offset), checked ((int)entry.Length)); if (entry.ItemId == METADATA_FILE_PARAMS) { fileParams = Program.ToStruct <VHDX_FILE_PARAMETERS>(entryBytes); } else if (entry.ItemId == METADATA_VIRTUAL_DISK_SIZE) { virtualDiskSize = Program.ToStruct <UInt64>(entryBytes); } else if (entry.ItemId == METADATA_LOGICAL_SECTOR_SIZE) { logicalSectorSize = Program.ToStruct <UInt32>(entryBytes); } } if (!fileParams.HasValue || !virtualDiskSize.HasValue || !logicalSectorSize.HasValue) { throw new Exception("Missing required metadata!"); } outFileParams = fileParams.Value; outVirtualDiskSize = checked ((long)virtualDiskSize.Value); outLogicalSectorSize = logicalSectorSize.Value; }
private void GetRegions(out VHDX_REGION_TABLE_ENTRY outBatRegion, out VHDX_REGION_TABLE_ENTRY outMetadataRegion) { UInt64 sig; mHdd.Get(0, out sig); if (sig != VHDX_SIG) throw new Exception("VHDX sig missing!"); var headers = new List<VHDX_HEADER>(); MaybeGetHeader(headers, HEADER_SIZE); MaybeGetHeader(headers, 2 * HEADER_SIZE); var head = headers.OrderByDescending(h => h.SequenceNumber).First(); if (head.Version != 1) throw new NotSupportedException($"Unsupported VHDX version: {head.Version}"); if (head.LogGuid != Guid.Empty) throw new NotImplementedException("Processing log entries is not supported."); //I'm assuming that both region tables are the same, so I just read the first one. var regionTableBytes = mHdd.ReadBytes(HEADER_SIZE * 3, HEADER_SIZE); var regionTable = Program.ToStruct<VHDX_REGION_TABLE_HEADER>(regionTableBytes); if (regionTable.Signature != REGION_TABLE_SIG) throw new Exception("Signature of region table is wrong!"); for (int i = 0; i < 4; i++) { regionTableBytes[i + 4] = 0; } if (regionTable.Checksum != Crc32CAlgorithm.Compute(regionTableBytes)) throw new Exception("Bad region table checksum!"); if (regionTable.EntryCount > 2047) throw new Exception("Too many region table entries!"); VHDX_REGION_TABLE_ENTRY? batRegion = null, metadataRegion = null; for (int i = 0; i < regionTable.EntryCount; i++) { int offset = Program.SizeOf<VHDX_REGION_TABLE_HEADER>() + i * Program.SizeOf<VHDX_REGION_TABLE_ENTRY>(); var entry = Program.ToStruct<VHDX_REGION_TABLE_ENTRY>(regionTableBytes, offset); if (entry.Guid == REGION_BAT) batRegion = entry; else if (entry.Guid == REGION_METADATA) metadataRegion = entry; else if (entry.Required) throw new Exception($"Unknown region: {entry.Guid}"); } if (!batRegion.HasValue) throw new Exception("Could not find BAT region!"); if (!metadataRegion.HasValue) throw new Exception("Could not find metadata region!"); outBatRegion = batRegion.Value; outMetadataRegion = metadataRegion.Value; }