public static void InitializeDisk(Disk disk, long firstUsableLBA, List <GuidPartitionEntry> partitionEntries) { MasterBootRecord mbr = new MasterBootRecord(); mbr.DiskSignature = (uint)new Random().Next(Int32.MaxValue); mbr.PartitionTable[0].PartitionTypeName = PartitionTypeName.EFIGPT; mbr.PartitionTable[0].FirstSectorLBA = 1; mbr.PartitionTable[0].SectorCountLBA = (uint)Math.Min(disk.TotalSectors - firstUsableLBA, UInt32.MaxValue); mbr.MBRSignature = 0xAA55; MasterBootRecord.WriteToDisk(disk, mbr); const int DefaultNumberOfEntries = 128; const int DefaultSizeOfEntry = 128; int partitionEntriesLength = DefaultNumberOfEntries * DefaultSizeOfEntry; long partitionEntriesPrimaryLBA = 2; long partitionEntriesSecondaryLBA = disk.TotalSectors - 1 - partitionEntriesLength / disk.BytesPerSector; GuidPartitionTableHeader primaryHeader = new GuidPartitionTableHeader(); primaryHeader.HeaderSize = 92; primaryHeader.CurrentLBA = 1; primaryHeader.BackupLBA = (ulong)(disk.TotalSectors - 1); primaryHeader.DiskGuid = Guid.NewGuid(); primaryHeader.FirstUsableLBA = (ulong)firstUsableLBA; primaryHeader.LastUsableLBA = (ulong)(partitionEntriesSecondaryLBA - 1); primaryHeader.PartitionEntriesLBA = (ulong)partitionEntriesPrimaryLBA; primaryHeader.NumberOfPartitionEntries = DefaultNumberOfEntries; primaryHeader.SizeOfPartitionEntry = DefaultSizeOfEntry; byte[] partitionTableEntries = new byte[partitionEntriesLength]; for (int index = 0; index < partitionEntries.Count; index++) { partitionEntries[index].WriteBytes(partitionTableEntries, index * DefaultSizeOfEntry); } primaryHeader.PartitionArrayCRC32 = CRC32.Compute(partitionTableEntries); GuidPartitionTableHeader secondaryHeader = primaryHeader.Clone(); secondaryHeader.CurrentLBA = (ulong)(disk.TotalSectors - 1); secondaryHeader.BackupLBA = 1; secondaryHeader.PartitionEntriesLBA = (ulong)partitionEntriesSecondaryLBA; GuidPartitionTableHeader.WriteToDisk(disk, primaryHeader); disk.WriteSectors(partitionEntriesPrimaryLBA, partitionTableEntries); GuidPartitionTableHeader.WriteToDisk(disk, secondaryHeader); disk.WriteSectors(partitionEntriesSecondaryLBA, partitionTableEntries); }
/// <summary> /// Read valid GPT (header and partition table), and write it to the correct locations at the beginning and end of the disk. /// The protective MBR partition size will be updated as well. /// </summary> public static void RebaseDisk(Disk disk, MasterBootRecord mbr) { GuidPartitionTableHeader primaryHeader = GuidPartitionTableHeader.ReadPrimaryFromDisk(disk); GuidPartitionTableHeader secondaryHeader = null; List <GuidPartitionEntry> entries = null; if (primaryHeader != null) { entries = ReadEntriesFromDisk(disk, primaryHeader); } if (primaryHeader == null || entries == null) { secondaryHeader = GuidPartitionTableHeader.ReadSecondaryFromDisk(disk, primaryHeader); if (secondaryHeader != null) { entries = ReadEntriesFromDisk(disk, secondaryHeader); } } if (entries == null) { throw new InvalidDataException("Both the primary and secondary GPT are corrupted"); } if (secondaryHeader != null) { primaryHeader = secondaryHeader.Clone(); } else { secondaryHeader = primaryHeader.Clone(); } byte[] partitionTableEntries = GuidPartitionEntryCollection.GetBytes(primaryHeader, entries); int partitionEntriesLength = (int)(primaryHeader.NumberOfPartitionEntries * primaryHeader.SizeOfPartitionEntry); long partitionEntriesPrimaryLBA = 2; long partitionEntriesSecondaryLBA = disk.TotalSectors - 1 - partitionEntriesLength / disk.BytesPerSector; // If the disk was trimmed or converted to GPT without a secondary header, we don't want to overwrite partition data bool writeSecondaryGPT = primaryHeader.LastUsableLBA <= (ulong)(partitionEntriesSecondaryLBA - 1); primaryHeader.CurrentLBA = 1; primaryHeader.BackupLBA = (ulong)(disk.TotalSectors - 1); primaryHeader.PartitionEntriesLBA = (ulong)partitionEntriesPrimaryLBA; primaryHeader.LastUsableLBA = (ulong)(partitionEntriesSecondaryLBA - 1); secondaryHeader.CurrentLBA = (ulong)(disk.TotalSectors - 1); secondaryHeader.BackupLBA = 1; secondaryHeader.PartitionEntriesLBA = (ulong)partitionEntriesSecondaryLBA; secondaryHeader.LastUsableLBA = (ulong)(partitionEntriesSecondaryLBA - 1); // Update protective MBR partition size uint firstUsableLBA = mbr.PartitionTable[0].FirstSectorLBA; mbr.PartitionTable[0].SectorCountLBA = (uint)Math.Min(disk.TotalSectors - firstUsableLBA, UInt32.MaxValue); MasterBootRecord.WriteToDisk(disk, mbr); // Write primary and secondary GPT GuidPartitionTableHeader.WriteToDisk(disk, primaryHeader); disk.WriteSectors(partitionEntriesPrimaryLBA, partitionTableEntries); if (writeSecondaryGPT) { GuidPartitionTableHeader.WriteToDisk(disk, secondaryHeader); disk.WriteSectors(partitionEntriesSecondaryLBA, partitionTableEntries); } }