using System.Collections.Generic; using System.IO; using System.Text; namespace DiskAccessLibrary { public class BddInfo { public const int BlockIndexEntrySize = 8; public string BasedImagePath { get; } public string SnapshotImagePath { get; } public long Length { get; } public int BlockSize { get; } public int NumberOfBlocks { get; } public long DataOffset { get; } public long EntryTableOffset { get; } public BlockEntryAllocateFlagIndexer Allocated { get; } public BlockEntryOffsetIndexer Offset { get; set; } public IReadOnlyList Entries { get; } public BddInfo(string snapshotImagePath, bool readEntries = true) { SnapshotImagePath = snapshotImagePath; using var fs = new FileStream(snapshotImagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using var reader = new BinaryReader(fs); int basedPathLength = reader.ReadUInt16(); //2 if (basedPathLength != 0) BasedImagePath = Encoding.UTF8.GetString(reader.ReadBytes(basedPathLength)); //N BlockSize = reader.ReadInt32(); //4 NumberOfBlocks = reader.ReadInt32(); //4 var snapMatchLength = NumberOfBlocks * (long)BlockSize; Length = snapMatchLength; if (false == readEntries) return; if (null != BasedImagePath) { if (false == File.Exists(BasedImagePath)) throw new FileNotFoundException("based image not found", BasedImagePath); using var ms = new FileStream(BasedImagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); if (snapMatchLength != ms.Length) throw new InvalidDataException("Snapshot size no match to based image"); } EntryTableOffset = fs.Position; var arr = new ulong[NumberOfBlocks]; for (var i = 0; i < NumberOfBlocks; i++) { arr[i] = reader.ReadUInt64(); } Entries = arr; DataOffset = fs.Position; Allocated = new BlockEntryAllocateFlagIndexer(arr); Offset = new BlockEntryOffsetIndexer(arr); } public static int CalcHeaderSize(string basedImagePath, int blockSize, out int blocks) { var baseLength = new FileInfo(basedImagePath).Length; blocks = (int)(baseLength / blockSize); return 2 + Encoding.UTF8.GetByteCount(basedImagePath) + 8 + blocks * BlockIndexEntrySize; } public static int CalcHeaderSize(long baseLength, int blockSize, out int blocks) { blocks = (int)(baseLength / blockSize); return 2 + +8 + blocks * BlockIndexEntrySize; } } }