internal DiskImageFileInfo(FileHeader fileHeader, VhdxHeader vhdxHeader1, VhdxHeader vhdxHeader2, RegionTable regions, Metadata metadata, LogSequence activeLogSequence) { _fileHeader = fileHeader; _vhdxHeader1 = vhdxHeader1; _vhdxHeader2 = vhdxHeader2; _regions = regions; _metadata = metadata; _activeLogSequence = activeLogSequence; }
private void ReadRegionTable() { _fileStream.Position = 192 * Sizes.OneKiB; _regionTable = Utilities.ReadStruct <RegionTable>(_fileStream); foreach (var entry in _regionTable.Regions.Values) { if ((entry.Flags & RegionFlags.Required) != 0) { if (entry.Guid != RegionTable.BatGuid && entry.Guid != RegionTable.MetadataRegionGuid) { throw new IOException("Invalid VHDX file - unrecognised required region"); } } _freeSpace.Reserve(entry.FileOffset, entry.Length); } }
private static void InitializeDynamicInternal(Stream stream, long capacity, long blockSize) { if (blockSize < Sizes.OneMiB || blockSize > Sizes.OneMiB * 256 || !Utilities.IsPowerOfTwo(blockSize)) { throw new ArgumentOutOfRangeException("blockSize", blockSize, "BlockSize must be a power of 2 between 1MB and 256MB"); } int logicalSectorSize = 512; int physicalSectorSize = 4096; long chunkRatio = (0x800000L * logicalSectorSize) / blockSize; long dataBlocksCount = Utilities.Ceil(capacity, blockSize); long sectorBitmapBlocksCount = Utilities.Ceil(dataBlocksCount, chunkRatio); long totalBatEntriesDynamic = dataBlocksCount + ((dataBlocksCount - 1) / chunkRatio); FileHeader fileHeader = new FileHeader() { Creator = ".NET DiscUtils" }; long fileEnd = Sizes.OneMiB; VhdxHeader header1 = new VhdxHeader(); header1.SequenceNumber = 0; header1.FileWriteGuid = Guid.NewGuid(); header1.DataWriteGuid = Guid.NewGuid(); header1.LogGuid = Guid.Empty; header1.LogVersion = 0; header1.Version = 1; header1.LogLength = (uint)Sizes.OneMiB; header1.LogOffset = (ulong)fileEnd; header1.CalcChecksum(); fileEnd += header1.LogLength; VhdxHeader header2 = new VhdxHeader(header1); header2.SequenceNumber = 1; header2.CalcChecksum(); RegionTable regionTable = new RegionTable(); RegionEntry metadataRegion = new RegionEntry(); metadataRegion.Guid = RegionEntry.MetadataRegionGuid; metadataRegion.FileOffset = fileEnd; metadataRegion.Length = (uint)Sizes.OneMiB; metadataRegion.Flags = RegionFlags.Required; regionTable.Regions.Add(metadataRegion.Guid, metadataRegion); fileEnd += metadataRegion.Length; RegionEntry batRegion = new RegionEntry(); batRegion.Guid = RegionEntry.BatGuid; batRegion.FileOffset = 3 * Sizes.OneMiB; batRegion.Length = (uint)Utilities.RoundUp(totalBatEntriesDynamic * 8, Sizes.OneMiB); batRegion.Flags = RegionFlags.Required; regionTable.Regions.Add(batRegion.Guid, batRegion); fileEnd += batRegion.Length; stream.Position = 0; Utilities.WriteStruct(stream, fileHeader); stream.Position = 64 * Sizes.OneKiB; Utilities.WriteStruct(stream, header1); stream.Position = 128 * Sizes.OneKiB; Utilities.WriteStruct(stream, header2); stream.Position = 192 * Sizes.OneKiB; Utilities.WriteStruct(stream, regionTable); stream.Position = 256 * Sizes.OneKiB; Utilities.WriteStruct(stream, regionTable); // Set stream to min size stream.Position = fileEnd - 1; stream.WriteByte(0); // Metadata FileParameters fileParams = new FileParameters() { BlockSize = (uint)blockSize, Flags = FileParametersFlags.None }; ParentLocator parentLocator = new ParentLocator(); Stream metadataStream = new SubStream(stream, metadataRegion.FileOffset, metadataRegion.Length); Metadata metadata = Metadata.Initialize(metadataStream, fileParams, (ulong)capacity, (uint)logicalSectorSize, (uint)physicalSectorSize, null); }
internal RegionTableInfo(RegionTable table) { _table = table; }
private void ReadRegionTable() { _fileStream.Position = 192 * Sizes.OneKiB; _regionTable = Utilities.ReadStruct<RegionTable>(_fileStream); foreach (var entry in _regionTable.Regions.Values) { if ((entry.Flags & RegionFlags.Required) != 0) { if (entry.Guid != RegionTable.BatGuid && entry.Guid != RegionTable.MetadataRegionGuid) { throw new IOException("Invalid VHDX file - unrecognised required region"); } } _freeSpace.Reserve(entry.FileOffset, entry.Length); } }
internal override List<BuilderExtent> FixExtents(out long totalLength) { if (_diskType != DiskType.Dynamic) { throw new NotSupportedException("Creation of only dynamic disks currently implemented"); } List<BuilderExtent> extents = new List<BuilderExtent>(); int logicalSectorSize = 512; int physicalSectorSize = 4096; long chunkRatio = (0x800000L * logicalSectorSize) / _blockSize; long dataBlocksCount = Utilities.Ceil(_content.Length, _blockSize); long sectorBitmapBlocksCount = Utilities.Ceil(dataBlocksCount, chunkRatio); long totalBatEntriesDynamic = dataBlocksCount + ((dataBlocksCount - 1) / chunkRatio); FileHeader fileHeader = new FileHeader() { Creator = ".NET DiscUtils" }; long fileEnd = Sizes.OneMiB; VhdxHeader header1 = new VhdxHeader(); header1.SequenceNumber = 0; header1.FileWriteGuid = Guid.NewGuid(); header1.DataWriteGuid = Guid.NewGuid(); header1.LogGuid = Guid.Empty; header1.LogVersion = 0; header1.Version = 1; header1.LogLength = (uint)Sizes.OneMiB; header1.LogOffset = (ulong)fileEnd; header1.CalcChecksum(); fileEnd += header1.LogLength; VhdxHeader header2 = new VhdxHeader(header1); header2.SequenceNumber = 1; header2.CalcChecksum(); RegionTable regionTable = new RegionTable(); RegionEntry metadataRegion = new RegionEntry(); metadataRegion.Guid = RegionEntry.MetadataRegionGuid; metadataRegion.FileOffset = fileEnd; metadataRegion.Length = (uint)Sizes.OneMiB; metadataRegion.Flags = RegionFlags.Required; regionTable.Regions.Add(metadataRegion.Guid, metadataRegion); fileEnd += metadataRegion.Length; RegionEntry batRegion = new RegionEntry(); batRegion.Guid = RegionEntry.BatGuid; batRegion.FileOffset = fileEnd; batRegion.Length = (uint)Utilities.RoundUp(totalBatEntriesDynamic * 8, Sizes.OneMiB); batRegion.Flags = RegionFlags.Required; regionTable.Regions.Add(batRegion.Guid, batRegion); fileEnd += batRegion.Length; extents.Add(ExtentForStruct(fileHeader, 0)); extents.Add(ExtentForStruct(header1, 64 * Sizes.OneKiB)); extents.Add(ExtentForStruct(header2, 128 * Sizes.OneKiB)); extents.Add(ExtentForStruct(regionTable, 192 * Sizes.OneKiB)); extents.Add(ExtentForStruct(regionTable, 256 * Sizes.OneKiB)); // Metadata FileParameters fileParams = new FileParameters() { BlockSize = (uint)_blockSize, Flags = FileParametersFlags.None }; ParentLocator parentLocator = new ParentLocator(); byte[] metadataBuffer = new byte[metadataRegion.Length]; MemoryStream metadataStream = new MemoryStream(metadataBuffer); Metadata.Initialize(metadataStream, fileParams, (ulong)_content.Length, (uint)logicalSectorSize, (uint)physicalSectorSize, null); extents.Add(new BuilderBufferExtent(metadataRegion.FileOffset, metadataBuffer)); List<Range<long, long>> presentBlocks = new List<Range<long, long>>(StreamExtent.Blocks(_content.Extents, _blockSize)); // BAT BlockAllocationTableBuilderExtent batExtent = new BlockAllocationTableBuilderExtent(batRegion.FileOffset, batRegion.Length, presentBlocks, fileEnd, _blockSize, chunkRatio); extents.Add(batExtent); // Stream contents foreach (var range in presentBlocks) { long substreamStart = range.Offset * _blockSize; long substreamCount = Math.Min(_content.Length - substreamStart, range.Count * _blockSize); SubStream dataSubStream = new SubStream(_content, substreamStart, substreamCount); BuilderSparseStreamExtent dataExtent = new BuilderSparseStreamExtent(fileEnd, dataSubStream); extents.Add(dataExtent); fileEnd += range.Count * _blockSize; } totalLength = fileEnd; return extents; }
internal override List <BuilderExtent> FixExtents(out long totalLength) { if (_diskType != DiskType.Dynamic) { throw new NotSupportedException("Creation of only dynamic disks currently implemented"); } List <BuilderExtent> extents = new List <BuilderExtent>(); int logicalSectorSize = 512; int physicalSectorSize = 4096; long chunkRatio = (0x800000L * logicalSectorSize) / _blockSize; long dataBlocksCount = Utilities.Ceil(_content.Length, _blockSize); long sectorBitmapBlocksCount = Utilities.Ceil(dataBlocksCount, chunkRatio); long totalBatEntriesDynamic = dataBlocksCount + ((dataBlocksCount - 1) / chunkRatio); FileHeader fileHeader = new FileHeader() { Creator = ".NET DiscUtils" }; long fileEnd = Sizes.OneMiB; VhdxHeader header1 = new VhdxHeader(); header1.SequenceNumber = 0; header1.FileWriteGuid = Guid.NewGuid(); header1.DataWriteGuid = Guid.NewGuid(); header1.LogGuid = Guid.Empty; header1.LogVersion = 0; header1.Version = 1; header1.LogLength = (uint)Sizes.OneMiB; header1.LogOffset = (ulong)fileEnd; header1.CalcChecksum(); fileEnd += header1.LogLength; VhdxHeader header2 = new VhdxHeader(header1); header2.SequenceNumber = 1; header2.CalcChecksum(); RegionTable regionTable = new RegionTable(); RegionEntry metadataRegion = new RegionEntry(); metadataRegion.Guid = RegionEntry.MetadataRegionGuid; metadataRegion.FileOffset = fileEnd; metadataRegion.Length = (uint)Sizes.OneMiB; metadataRegion.Flags = RegionFlags.Required; regionTable.Regions.Add(metadataRegion.Guid, metadataRegion); fileEnd += metadataRegion.Length; RegionEntry batRegion = new RegionEntry(); batRegion.Guid = RegionEntry.BatGuid; batRegion.FileOffset = fileEnd; batRegion.Length = (uint)Utilities.RoundUp(totalBatEntriesDynamic * 8, Sizes.OneMiB); batRegion.Flags = RegionFlags.Required; regionTable.Regions.Add(batRegion.Guid, batRegion); fileEnd += batRegion.Length; extents.Add(ExtentForStruct(fileHeader, 0)); extents.Add(ExtentForStruct(header1, 64 * Sizes.OneKiB)); extents.Add(ExtentForStruct(header2, 128 * Sizes.OneKiB)); extents.Add(ExtentForStruct(regionTable, 192 * Sizes.OneKiB)); extents.Add(ExtentForStruct(regionTable, 256 * Sizes.OneKiB)); // Metadata FileParameters fileParams = new FileParameters() { BlockSize = (uint)_blockSize, Flags = FileParametersFlags.None }; ParentLocator parentLocator = new ParentLocator(); byte[] metadataBuffer = new byte[metadataRegion.Length]; MemoryStream metadataStream = new MemoryStream(metadataBuffer); Metadata.Initialize(metadataStream, fileParams, (ulong)_content.Length, (uint)logicalSectorSize, (uint)physicalSectorSize, null); extents.Add(new BuilderBufferExtent(metadataRegion.FileOffset, metadataBuffer)); List <Range <long, long> > presentBlocks = new List <Range <long, long> >(StreamExtent.Blocks(_content.Extents, _blockSize)); // BAT BlockAllocationTableBuilderExtent batExtent = new BlockAllocationTableBuilderExtent(batRegion.FileOffset, batRegion.Length, presentBlocks, fileEnd, _blockSize, chunkRatio); extents.Add(batExtent); // Stream contents foreach (var range in presentBlocks) { long substreamStart = range.Offset * _blockSize; long substreamCount = Math.Min(_content.Length - substreamStart, range.Count * _blockSize); SubStream dataSubStream = new SubStream(_content, substreamStart, substreamCount); BuilderSparseStreamExtent dataExtent = new BuilderSparseStreamExtent(fileEnd, dataSubStream); extents.Add(dataExtent); fileEnd += range.Count * _blockSize; } totalLength = fileEnd; return(extents); }