public static bool TryGetMbrInfo(DiskImage hdd, out MbrPartitioningInfo info) { info = default; Debug.Assert(Unsafe.SizeOf <MbrHeader>() == MBR_SIZE); var headerBytes = hdd.ReadBytes(0, MBR_SIZE); MbrHeader header = MemoryMarshal.Cast <byte, MbrHeader>(new Span <byte>(headerBytes))[0]; if (header.BootSig != MbrHeader.MbrMagic) { return(false); } bool hasGpt = false; for (int i = 0; i < 4; i++) { var part = header.GetPartition(i); hasGpt |= part.Type == MbrPartitionType.GptProtective; } //MBR paritioned disks often contain boot loaders in non-paritioned space. //So to be safe copy all the data. List <FileExtent> partitions = new List <FileExtent>() { new FileExtent(MBR_SIZE, hdd.Length - MBR_SIZE), }; info = new MbrPartitioningInfo(headerBytes, partitions, hasGpt); return(true); }
static bool getParitionInfo(DiskImage image, out IPartitioningInfo info) { GptPartitioningInfo gpt; if (GptPartitioningInfo.TryGetGptInfo(image, out gpt)) { info = gpt; return(true); } MbrPartitioningInfo mbr; if (MbrPartitioningInfo.TryGetMbrInfo(image, out mbr)) { info = mbr; return(true); } info = null; return(false); }
public static bool TryGetGptInfo(DiskImage hdd, out GptPartitioningInfo info) { Debug.Assert(Unsafe.SizeOf <GptHeader>() == CurrentHeaderSize); Debug.Assert(Unsafe.SizeOf <PartitionEntry>() == PartitionEntrySize); info = null; MbrPartitioningInfo mbr; if (!MbrPartitioningInfo.TryGetMbrInfo(hdd, out mbr)) { return(false); } if (!mbr.HasGpt) { return(false); } var primaryHeader = LoadHeader(hdd, SectorSize); var backupHeader = LoadHeader(hdd, hdd.Length - SectorSize); //Make sure the headers agree on each other's locations if (primaryHeader.BackupLba != (hdd.Length / SectorSize) - 1) { throw new Exception("Location of backup LBA in primary header is wrong."); } if (backupHeader.BackupLba != 1) { throw new Exception("Location of primary LBA in backup header is wrong."); } //make sure the headers match if (primaryHeader.NumberOfPartitions != backupHeader.NumberOfPartitions) { throw new Exception("Primary and backup GPT headers do not agree on the number of partitions."); } if (primaryHeader.FirstUsableLba != backupHeader.FirstUsableLba || primaryHeader.LastUsableLba != backupHeader.LastUsableLba) { throw new Exception("Primary and backup GPT headers do not agree on the usable area of the disk."); } if (primaryHeader.DiskGuid != backupHeader.DiskGuid) { throw new Exception("Primary and backup GPT headers do not agree on the disk GUID."); } //TODO: Make sure the partition entries do not intersect with the usable area of the disk or the GptHeader. //at this point we have varified that the header for both the primary and backup //GPT are correct. We are only going to load paritions from the primary header. //Make sure the minimum space for partition entries was reserved if (primaryHeader.FirstUsableLba < (Program.RoundUp(MinimumSizeForParitionEntriesArea, SectorSize) / SectorSize + 2)) //extra two sectors for protective MBR and GPT header { throw new Exception("Not enough space for primary parition entries was reserved."); } if (primaryHeader.LastUsableLba >= Program.RoundDown(hdd.Length - MinimumSizeForParitionEntriesArea - SectorSize, SectorSize) / SectorSize) { throw new Exception("Not enough space for backup parition entries was reserved."); } byte[] partitionEntriesBytes = new byte[primaryHeader.NumberOfPartitions * PartitionEntrySize]; hdd.ReadBytes(new Span <byte>(partitionEntriesBytes), primaryHeader.StartingLbaOfPartitionEntries * SectorSize); uint actualEntriesCrc = Crc32Algorithm.Compute(partitionEntriesBytes); if (primaryHeader.CrcOfPartitionEntry != actualEntriesCrc) { throw new Exception("CRC of partition entries not correct."); } var partitions = new List <PartitionEntry>(); foreach (PartitionEntry part in MemoryMarshal.Cast <byte, PartitionEntry>(new ReadOnlySpan <byte>(partitionEntriesBytes))) { if (part.Type == Guid.Empty) { continue; } if (part.FirstLba < primaryHeader.FirstUsableLba || part.LastLba > primaryHeader.LastUsableLba) { throw new Exception($"Parition '{part.Name}' is outside the usable space."); } partitions.Add(part); } partitions.Sort((a, b) => a.FirstLba.CompareTo(b.FirstLba)); //TODO: make sure the paritions do not intersect with each other info = new GptPartitioningInfo(mbr, partitions); return(true); }
private GptPartitioningInfo(MbrPartitioningInfo protectiveMbr, List <PartitionEntry> partitions) { this.mProtectiveMbr = protectiveMbr; this.mPartitions = partitions; }