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); }
private static List <GuidPartitionEntry> ReadEntriesFromDisk(Disk disk, GuidPartitionTableHeader header) { int bufferLength = (int)(header.NumberOfPartitionEntries * header.SizeOfPartitionEntry); int sectorsToRead = (int)Math.Ceiling((double)bufferLength / disk.BytesPerSector); byte[] buffer = disk.ReadSectors((long)header.PartitionEntriesLBA, sectorsToRead); if (buffer.Length > bufferLength) { buffer = ByteReader.ReadBytes(buffer, 0, bufferLength); } uint expectedCRC32 = CRC32.Compute(buffer); if (header.PartitionArrayCRC32 != expectedCRC32) { return(null); } int offset = 0; List <GuidPartitionEntry> result = new List <GuidPartitionEntry>(); for (int index = 0; index < header.NumberOfPartitionEntries; index++) { GuidPartitionEntry entry = new GuidPartitionEntry(buffer, offset); entry.EntryIndex = index; // Unused entries use Guid.Empty as PartitionTypeGuid if (entry.PartitionTypeGuid != Guid.Empty) { result.Add(entry); } offset += (int)header.SizeOfPartitionEntry; } return(result); }
public static void WriteToDisk(Disk disk, GuidPartitionTableHeader header, GuidPartitionEntry entry) { long sectorIndex = (long)header.PartitionEntriesLBA + entry.EntryIndex * header.SizeOfPartitionEntry / disk.BytesPerSector; int entriesPerSector = (int)(disk.BytesPerSector / header.SizeOfPartitionEntry); int indexInSector = (int)(entry.EntryIndex % entriesPerSector); byte[] buffer = disk.ReadSector(sectorIndex); entry.WriteBytes(buffer, indexInSector * (int)header.SizeOfPartitionEntry); disk.WriteSectors(sectorIndex, buffer); }
public static void InitializeDisk(Disk disk, long firstUsableLBA, long reservedPartitionSizeLBA) { if (reservedPartitionSizeLBA > 0 && reservedPartitionSizeLBA * disk.BytesPerSector < 1024 * 1024) { // The LDM database will take 1MB out of the reserved partition. // less than 1MB will cause the conversion to dynamic disk to fail. throw new ArgumentException("Reserved partition size must be at least 1MB"); } List <GuidPartitionEntry> partitionEntries = new List <GuidPartitionEntry>(); if (reservedPartitionSizeLBA > 0) { GuidPartitionEntry reservedEntry = new GuidPartitionEntry(); reservedEntry.PartitionGuid = Guid.NewGuid(); reservedEntry.PartitionTypeGuid = GPTPartition.MicrosoftReservedPartititionTypeGuid; reservedEntry.FirstLBA = (ulong)firstUsableLBA; reservedEntry.LastLBA = (ulong)(firstUsableLBA + reservedPartitionSizeLBA - 1); reservedEntry.PartitionName = "Microsoft reserved partition"; partitionEntries.Add(reservedEntry); } InitializeDisk(disk, firstUsableLBA, partitionEntries); }