Esempio n. 1
0
        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;
        }
Esempio n. 2
0
        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;
        }
Esempio n. 3
0
        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;
        }
Esempio n. 4
0
        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;
        }