private static void InitializeDifferencingInternal(Stream stream, DiskImageFile parent, string parentAbsolutePath, string parentRelativePath, DateTime parentModificationTimeUtc) { Footer footer = new Footer(parent.Geometry, parent._footer.CurrentSize, FileType.Differencing); footer.DataOffset = 512; // Offset of Dynamic Header footer.OriginalSize = parent._footer.OriginalSize; footer.UpdateChecksum(); byte[] footerBlock = new byte[512]; footer.ToBytes(footerBlock, 0); long tableOffset = 512 + 1024; // Footer + Header uint blockSize = (parent._dynamicHeader == null) ? DynamicHeader.DefaultBlockSize : parent._dynamicHeader.BlockSize; DynamicHeader dynamicHeader = new DynamicHeader(-1, tableOffset, blockSize, footer.CurrentSize); int batSize = (((dynamicHeader.MaxTableEntries * 4) + Utilities.SectorSize - 1) / Utilities.SectorSize) * Utilities.SectorSize; dynamicHeader.ParentUniqueId = parent.UniqueId; dynamicHeader.ParentTimestamp = parentModificationTimeUtc; dynamicHeader.ParentUnicodeName = Utilities.GetFileFromPath(parentAbsolutePath); dynamicHeader.ParentLocators[7].PlatformCode = ParentLocator.PlatformCodeWindowsAbsoluteUnicode; dynamicHeader.ParentLocators[7].PlatformDataSpace = 512; dynamicHeader.ParentLocators[7].PlatformDataLength = parentAbsolutePath.Length * 2; dynamicHeader.ParentLocators[7].PlatformDataOffset = tableOffset + batSize; dynamicHeader.ParentLocators[6].PlatformCode = ParentLocator.PlatformCodeWindowsRelativeUnicode; dynamicHeader.ParentLocators[6].PlatformDataSpace = 512; dynamicHeader.ParentLocators[6].PlatformDataLength = parentRelativePath.Length * 2; dynamicHeader.ParentLocators[6].PlatformDataOffset = tableOffset + batSize + 512; dynamicHeader.UpdateChecksum(); byte[] dynamicHeaderBlock = new byte[1024]; dynamicHeader.ToBytes(dynamicHeaderBlock, 0); byte[] platformLocator1 = new byte[512]; Encoding.Unicode.GetBytes(parentAbsolutePath, 0, parentAbsolutePath.Length, platformLocator1, 0); byte[] platformLocator2 = new byte[512]; Encoding.Unicode.GetBytes(parentRelativePath, 0, parentRelativePath.Length, platformLocator2, 0); byte[] bat = new byte[batSize]; for (int i = 0; i < bat.Length; ++i) { bat[i] = 0xFF; } stream.Position = 0; stream.Write(footerBlock, 0, 512); stream.Write(dynamicHeaderBlock, 0, 1024); stream.Write(bat, 0, batSize); stream.Write(platformLocator1, 0, 512); stream.Write(platformLocator2, 0, 512); stream.Write(footerBlock, 0, 512); }
internal override List<BuilderExtent> FixExtents(out long totalLength) { const int FooterSize = 512; const int DynHeaderSize = 1024; List<BuilderExtent> extents = new List<BuilderExtent>(); _footer.DataOffset = FooterSize; DynamicHeader dynHeader = new DynamicHeader(-1, FooterSize + DynHeaderSize, _blockSize, _footer.CurrentSize); BlockAllocationTableExtent batExtent = new BlockAllocationTableExtent(FooterSize + DynHeaderSize, dynHeader.MaxTableEntries); long streamPos = batExtent.Start + batExtent.Length; foreach (var blockRange in StreamExtent.Blocks(_content.Extents, _blockSize)) { for (int i = 0; i < blockRange.Count; ++i) { long block = blockRange.Offset + i; long blockStart = block * _blockSize; DataBlockExtent dataExtent = new DataBlockExtent(streamPos, new SubStream(_content, blockStart, Math.Min(_blockSize, _content.Length - blockStart))); extents.Add(dataExtent); batExtent.SetEntry((int)block, (uint)(streamPos / Sizes.Sector)); streamPos += dataExtent.Length; } } _footer.UpdateChecksum(); dynHeader.UpdateChecksum(); byte[] footerBuffer = new byte[FooterSize]; _footer.ToBytes(footerBuffer, 0); byte[] dynHeaderBuffer = new byte[DynHeaderSize]; dynHeader.ToBytes(dynHeaderBuffer, 0); // Add footer (to end) extents.Add(new BuilderBufferExtent(streamPos, footerBuffer)); totalLength = streamPos + FooterSize; extents.Insert(0, batExtent); extents.Insert(0, new BuilderBufferExtent(FooterSize, dynHeaderBuffer)); extents.Insert(0, new BuilderBufferExtent(0, footerBuffer)); return extents; }
internal override List <BuilderExtent> FixExtents(out long totalLength) { const int FooterSize = 512; const int DynHeaderSize = 1024; List <BuilderExtent> extents = new List <BuilderExtent>(); _footer.DataOffset = FooterSize; DynamicHeader dynHeader = new DynamicHeader(-1, FooterSize + DynHeaderSize, _blockSize, _footer.CurrentSize); BlockAllocationTableExtent batExtent = new BlockAllocationTableExtent(FooterSize + DynHeaderSize, dynHeader.MaxTableEntries); long streamPos = batExtent.Start + batExtent.Length; foreach (var blockRange in StreamExtent.Blocks(_content.Extents, _blockSize)) { for (int i = 0; i < blockRange.Count; ++i) { long block = blockRange.Offset + i; long blockStart = block * _blockSize; DataBlockExtent dataExtent = new DataBlockExtent(streamPos, new SubStream(_content, blockStart, Math.Min(_blockSize, _content.Length - blockStart))); extents.Add(dataExtent); batExtent.SetEntry((int)block, (uint)(streamPos / Sizes.Sector)); streamPos += dataExtent.Length; } } _footer.UpdateChecksum(); dynHeader.UpdateChecksum(); byte[] footerBuffer = new byte[FooterSize]; _footer.ToBytes(footerBuffer, 0); byte[] dynHeaderBuffer = new byte[DynHeaderSize]; dynHeader.ToBytes(dynHeaderBuffer, 0); // Add footer (to end) extents.Add(new BuilderBufferExtent(streamPos, footerBuffer)); totalLength = streamPos + FooterSize; extents.Insert(0, batExtent); extents.Insert(0, new BuilderBufferExtent(FooterSize, dynHeaderBuffer)); extents.Insert(0, new BuilderBufferExtent(0, footerBuffer)); return(extents); }
public DynamicHeader(DynamicHeader toCopy) { Cookie = toCopy.Cookie; DataOffset = toCopy.DataOffset; TableOffset = toCopy.TableOffset; HeaderVersion = toCopy.HeaderVersion; MaxTableEntries = toCopy.MaxTableEntries; BlockSize = toCopy.BlockSize; Checksum = toCopy.Checksum; ParentUniqueId = toCopy.ParentUniqueId; ParentTimestamp = toCopy.ParentTimestamp; ParentUnicodeName = toCopy.ParentUnicodeName; ParentLocators = new ParentLocator[toCopy.ParentLocators.Length]; for (int i = 0; i < ParentLocators.Length; ++i) { ParentLocators[i] = new ParentLocator(toCopy.ParentLocators[i]); } }
private uint CalculateChecksum() { DynamicHeader copy = new DynamicHeader(this); copy.Checksum = 0; byte[] asBytes = new byte[1024]; copy.ToBytes(asBytes, 0); uint checksum = 0; foreach (uint value in asBytes) { checksum += value; } checksum = ~checksum; return(checksum); }
private void ReadHeaders() { long pos = _footer.DataOffset; while (pos != -1) { _fileStream.Position = pos; Header hdr = Header.FromStream(_fileStream); if (hdr.Cookie == DynamicHeader.HeaderCookie) { _fileStream.Position = pos; _dynamicHeader = DynamicHeader.FromStream(_fileStream); if (!_dynamicHeader.IsValid()) { throw new IOException("Invalid Dynamic Disc Header"); } } pos = hdr.DataOffset; } }
public DynamicStream(Stream fileStream, DynamicHeader dynamicHeader, long length, SparseStream parentStream, Ownership ownsParentStream) { if (fileStream == null) { throw new ArgumentNullException("fileStream"); } if (dynamicHeader == null) { throw new ArgumentNullException("dynamicHeader"); } if (parentStream == null) { throw new ArgumentNullException("parentStream"); } if (length < 0) { throw new ArgumentOutOfRangeException("length", length, "Negative lengths not allowed"); } _fileStream = fileStream; _dynamicHeader = dynamicHeader; _length = length; _parentStream = parentStream; _ownsParentStream = ownsParentStream; _blockBitmaps = new byte[_dynamicHeader.MaxTableEntries][]; _blockBitmapSize = (int)Utilities.RoundUp((_dynamicHeader.BlockSize / Utilities.SectorSize) / 8, Utilities.SectorSize); ReadBlockAllocationTable(); // Detect where next block should go (cope if the footer is missing) _fileStream.Position = Utilities.RoundDown(_fileStream.Length, Utilities.SectorSize) - Utilities.SectorSize; byte[] footerBytes = Utilities.ReadFully(_fileStream, Utilities.SectorSize); Footer footer = Footer.FromBytes(footerBytes, 0); _nextBlockStart = _fileStream.Position - (footer.IsValid() ? Utilities.SectorSize : 0); }
private static void InitializeDynamicInternal(Stream stream, long capacity, Geometry geometry, long blockSize) { if (blockSize > uint.MaxValue || blockSize < 0) { throw new ArgumentOutOfRangeException("blockSize", "Must be in the range 0 to uint.MaxValue"); } if (geometry == null) { geometry = Geometry.FromCapacity(capacity); } Footer footer = new Footer(geometry, capacity, FileType.Dynamic); footer.DataOffset = 512; // Offset of Dynamic Header footer.UpdateChecksum(); byte[] footerBlock = new byte[512]; footer.ToBytes(footerBlock, 0); DynamicHeader dynamicHeader = new DynamicHeader(-1, 1024 + 512, (uint)blockSize, capacity); dynamicHeader.UpdateChecksum(); byte[] dynamicHeaderBlock = new byte[1024]; dynamicHeader.ToBytes(dynamicHeaderBlock, 0); int batSize = (((dynamicHeader.MaxTableEntries * 4) + Utilities.SectorSize - 1) / Utilities.SectorSize) * Utilities.SectorSize; byte[] bat = new byte[batSize]; for (int i = 0; i < bat.Length; ++i) { bat[i] = 0xFF; } stream.Position = 0; stream.Write(footerBlock, 0, 512); stream.Write(dynamicHeaderBlock, 0, 1024); stream.Write(bat, 0, batSize); stream.Write(footerBlock, 0, 512); }
public static DynamicHeader FromBytes(byte[] data, int offset) { DynamicHeader result = new DynamicHeader(); result.Cookie = Utilities.BytesToString(data, offset, 8); result.DataOffset = Utilities.ToInt64BigEndian(data, offset + 8); result.TableOffset = Utilities.ToInt64BigEndian(data, offset + 16); result.HeaderVersion = Utilities.ToUInt32BigEndian(data, offset + 24); result.MaxTableEntries = Utilities.ToInt32BigEndian(data, offset + 28); result.BlockSize = Utilities.ToUInt32BigEndian(data, offset + 32); result.Checksum = Utilities.ToUInt32BigEndian(data, offset + 36); result.ParentUniqueId = Utilities.ToGuidBigEndian(data, offset + 40); result.ParentTimestamp = Footer.EpochUtc.AddSeconds(Utilities.ToUInt32BigEndian(data, offset + 56)); result.ParentUnicodeName = Encoding.BigEndianUnicode.GetString(data, offset + 64, 512).TrimEnd('\0'); result.ParentLocators = new ParentLocator[8]; for (int i = 0; i < 8; ++i) { result.ParentLocators[i] = ParentLocator.FromBytes(data, offset + 576 + (i * 24)); } return(result); }
private void CheckDynamicHeader() { long lastHeaderEnd = _footer.DataOffset + 512; long pos = _footer.DataOffset; while (pos != -1) { if ((pos % 512) != 0) { ReportError("DynHeader: Unaligned header @{0}", pos); } _fileStream.Position = pos; Header hdr = Header.FromStream(_fileStream); if (hdr.Cookie == DynamicHeader.HeaderCookie) { if (_dynamicHeader != null) { ReportError("DynHeader: Duplicate dynamic header found"); } _fileStream.Position = pos; _dynamicHeader = DynamicHeader.FromStream(_fileStream); if (pos + 1024 > lastHeaderEnd) { lastHeaderEnd = pos + 1024; } } else { ReportWarning("DynHeader: Undocumented header found, with cookie '" + hdr.Cookie + "'"); if (pos + 512 > lastHeaderEnd) { lastHeaderEnd = pos + 1024; } } pos = hdr.DataOffset; } if (_dynamicHeader == null) { ReportError("DynHeader: No dynamic header found"); return; } if (_dynamicHeader.TableOffset < lastHeaderEnd) { ReportError("DynHeader: BAT offset is before last header"); } if ((_dynamicHeader.TableOffset % 512) != 0) { ReportError("DynHeader: BAT offset is not sector aligned"); } if (_dynamicHeader.HeaderVersion != 0x00010000) { ReportError("DynHeader: Unrecognized header version"); } if (_dynamicHeader.MaxTableEntries != Utilities.Ceil(_footer.CurrentSize, _dynamicHeader.BlockSize)) { ReportError("DynHeader: Max table entries is invalid"); } if ((_dynamicHeader.BlockSize != Sizes.OneMiB * 2) && (_dynamicHeader.BlockSize != Sizes.OneKiB * 512)) { ReportWarning("DynHeader: Using non-standard block size '" + _dynamicHeader.BlockSize + "'"); } if (!Utilities.IsPowerOfTwo(_dynamicHeader.BlockSize)) { ReportError("DynHeader: Block size is not a power of 2"); } if (!_dynamicHeader.IsChecksumValid()) { ReportError("DynHeader: Invalid checksum"); } if (_footer.DiskType == FileType.Dynamic && _dynamicHeader.ParentUniqueId != Guid.Empty) { ReportWarning("DynHeader: Parent Id is not null for dynamic disk"); } else if (_footer.DiskType == FileType.Differencing && _dynamicHeader.ParentUniqueId == Guid.Empty) { ReportError("DynHeader: Parent Id is null for differencing disk"); } if (_footer.DiskType == FileType.Differencing && _dynamicHeader.ParentTimestamp > DateTime.UtcNow) { ReportWarning("DynHeader: Parent timestamp is greater than current time"); } }
internal DiskImageFileInfo(Footer footer, DynamicHeader header, Stream vhdStream) { _footer = footer; _header = header; _vhdStream = vhdStream; }
private uint CalculateChecksum() { DynamicHeader copy = new DynamicHeader(this); copy.Checksum = 0; byte[] asBytes = new byte[1024]; copy.ToBytes(asBytes, 0); uint checksum = 0; foreach (uint value in asBytes) { checksum += value; } checksum = ~checksum; return checksum; }
public static DynamicHeader FromBytes(byte[] data, int offset) { DynamicHeader result = new DynamicHeader(); result.Cookie = Utilities.BytesToString(data, offset, 8); result.DataOffset = Utilities.ToInt64BigEndian(data, offset + 8); result.TableOffset = Utilities.ToInt64BigEndian(data, offset + 16); result.HeaderVersion = Utilities.ToUInt32BigEndian(data, offset + 24); result.MaxTableEntries = Utilities.ToInt32BigEndian(data, offset + 28); result.BlockSize = Utilities.ToUInt32BigEndian(data, offset + 32); result.Checksum = Utilities.ToUInt32BigEndian(data, offset + 36); result.ParentUniqueId = Utilities.ToGuidBigEndian(data, offset + 40); result.ParentTimestamp = Footer.EpochUtc.AddSeconds(Utilities.ToUInt32BigEndian(data, offset + 56)); result.ParentUnicodeName = Encoding.BigEndianUnicode.GetString(data, offset + 64, 512).TrimEnd('\0'); result.ParentLocators = new ParentLocator[8]; for (int i = 0; i < 8; ++i) { result.ParentLocators[i] = ParentLocator.FromBytes(data, offset + 576 + (i * 24)); } return result; }