public void BuildStreamLengthIsRespected() { int length = 1024; var extent = new BuilderSparseStreamExtent(0, new ZeroStream(2 * length)); using (var stream = new BuiltStream(length, new List <BuilderExtent> { extent })) { Assert.Equal(0, stream.Position); Assert.Equal(length, stream.Length); var content = new byte[2 * length]; var read = stream.Read(content, 0, content.Length); Assert.Equal(length, read); Assert.Equal(stream.Length, stream.Position); } }
/// <summary> /// Sets a stream representing the content of a partition in the partition table. /// </summary> /// <param name="index">The index of the partition</param> /// <param name="stream">The stream with the contents of the partition</param> public void SetPartitionContent(int index, SparseStream stream) { _partitionContents[index] = new BuilderSparseStreamExtent(_partitionTable[index].FirstSector * Sizes.Sector, stream); }
/// <summary> /// Sets a stream representing the content of a partition in the partition table. /// </summary> /// <param name="index">The index of the partition</param> /// <param name="stream">The stream with the contents of the partition</param> public void SetPartitionContent(int index, SparseStream stream) { _partitionContents[index] = new BuilderSparseStreamExtent(_partitionTable[index].FirstSector * Sizes.Sector, stream); }
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); }