public static void ExtendGPTPartition(GPTPartition partition, long numberOfAdditionalExtentSectors) { Disk disk = partition.Disk; GuidPartitionTableHeader primaryHeader = GuidPartitionTableHeader.ReadPrimaryFromDisk(disk); GuidPartitionTableHeader secondaryHeader = GuidPartitionTableHeader.ReadSecondaryFromDisk(disk, primaryHeader); if (primaryHeader == null || secondaryHeader == null) { throw new NotImplementedException("Cannot extend GPT disk with corrupted header"); } if (primaryHeader.PartitionArrayCRC32 != secondaryHeader.PartitionArrayCRC32) { throw new NotImplementedException("Cannot extend GPT disk with mismatched partition arrays"); } List <GuidPartitionEntry> entries = GuidPartitionTable.ReadEntriesFromDisk(disk); foreach (GuidPartitionEntry entry in entries) { if ((long)entry.FirstLBA == partition.FirstSector) { entry.LastLBA += (ulong)numberOfAdditionalExtentSectors; GuidPartitionEntry.WriteToDisk(disk, primaryHeader, entry); GuidPartitionEntry.WriteToDisk(disk, secondaryHeader, entry); break; } } primaryHeader.PartitionArrayCRC32 = GuidPartitionTable.ComputePartitionArrayCRC32(disk, primaryHeader); GuidPartitionTableHeader.WriteToDisk(disk, primaryHeader); secondaryHeader.PartitionArrayCRC32 = GuidPartitionTable.ComputePartitionArrayCRC32(disk, secondaryHeader); GuidPartitionTableHeader.WriteToDisk(disk, secondaryHeader); }
public static List <GuidPartitionEntry> ReadEntriesFromDisk(Disk disk) { GuidPartitionTableHeader primaryHeader = GuidPartitionTableHeader.ReadPrimaryFromDisk(disk); if (primaryHeader != null) { List <GuidPartitionEntry> result = ReadEntriesFromDisk(disk, primaryHeader); if (result != null) { return(result); } } GuidPartitionTableHeader secondaryHeader = GuidPartitionTableHeader.ReadSecondaryFromDisk(disk, primaryHeader); if (secondaryHeader != null) { return(ReadEntriesFromDisk(disk, secondaryHeader)); } return(null); }
/// <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); } }