public static List <DiskExtent> GetUnallocatedExtents(Disk disk) { MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(disk); List <DiskExtent> result = new List <DiskExtent>(); if (mbr == null) { result.Add(new DiskExtent(disk, 0, disk.Size)); return(result); } else { long dataRegionStartSector; long dataRegionSize; if (!mbr.IsGPTBasedDisk) { dataRegionStartSector = MBRDiskFirstUsableSector; dataRegionSize = Math.Min(disk.Size, UInt32.MaxValue * disk.BytesPerSector) - dataRegionStartSector; } else { GuidPartitionTableHeader gptHeader = GuidPartitionTableHeader.ReadFromDisk(disk); dataRegionStartSector = (long)gptHeader.FirstUsableLBA; dataRegionSize = (long)(gptHeader.LastUsableLBA - gptHeader.FirstUsableLBA + 1) * disk.BytesPerSector; } List <Partition> partitions = GetPartitions(disk); List <DiskExtent> usedExtents = new List <DiskExtent>(); foreach (Partition partition in partitions) { usedExtents.Add(partition.Extent); } return(DiskExtentsHelper.GetUnallocatedExtents(disk, dataRegionStartSector, dataRegionSize, usedExtents)); } }
public static Guid?GetWindowsVolumeGuid(Volume volume) { if (volume is MBRPartition) { MBRPartition partition = (MBRPartition)volume; MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(((MBRPartition)volume).Disk); return(GetWindowsVolumeGuid(mbr.DiskSignature, (ulong)(partition.FirstSector * partition.BytesPerSector))); } else if (volume is GPTPartition) { return(((GPTPartition)volume).VolumeGuid); } else if (volume is DynamicVolume) { return(((DynamicVolume)volume).VolumeGuid); } else if (volume is OperatingSystemVolume) { return(((OperatingSystemVolume)volume).VolumeGuid); } else { return(null); } }
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); }
public static void ExtendMBRPartition(MBRPartition partition, long numberOfAdditionalExtentSectors) { Disk disk = partition.Disk; MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(disk); for (int index = 0; index < mbr.PartitionTable.Length; index++) { if (mbr.PartitionTable[index].FirstSectorLBA == partition.FirstSector) { mbr.PartitionTable[index].SectorCountLBA += (uint)numberOfAdditionalExtentSectors; ulong lastSectorLBA = mbr.PartitionTable[index].LastSectorLBA; mbr.PartitionTable[index].LastSectorCHS = CHSAddress.FromLBA(lastSectorLBA, disk); break; } } MasterBootRecord.WriteToDisk(disk, mbr); }
/// <returns>Number of bytes</returns> public static long GetMaximumSizeToExtendMBRPartition(MBRPartition partition) { MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(partition.Disk); long partitonEndSector = partition.FirstSector + partition.Size / partition.BytesPerSector; long max = partition.Disk.Size - (partition.FirstSector * partition.BytesPerSector + partition.Size); foreach (PartitionTableEntry entry in mbr.PartitionTable) { if (entry.FirstSectorLBA > partition.FirstSector) { long available = (entry.FirstSectorLBA - partition.FirstSector) * partition.BytesPerSector - partition.Size; max = Math.Min(max, available); } } // MBR partition cannot be larger than 2^32 sectors max = Math.Min(max, UInt32.MaxValue * partition.BytesPerSector); return(max); }
public static Guid?GetVolumeUniqueID(Volume volume) { if (volume is MBRPartition) { MBRPartition partition = (MBRPartition)volume; MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(partition.Disk); byte[] firstSectorBytes = BigEndianConverter.GetBytes(partition.FirstSector); return(new Guid((int)mbr.DiskSignature, 0, 0, firstSectorBytes)); } else if (volume is GPTPartition) { return(((GPTPartition)volume).VolumeGuid); } else if (volume is DynamicVolume) { return(((DynamicVolume)volume).VolumeGuid); } else { return(null); } }
public static List <Partition> GetPartitions(Disk disk) { List <Partition> result = new List <Partition>(); MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(disk); if (mbr != null) { if (!mbr.IsGPTBasedDisk) { for (int index = 0; index < mbr.PartitionTable.Length; index++) { PartitionTableEntry entry = mbr.PartitionTable[index]; if (entry.SectorCountLBA > 0) { long size = entry.SectorCountLBA * disk.BytesPerSector; MBRPartition partition = new MBRPartition(entry.PartitionType, disk, entry.FirstSectorLBA, size); result.Add(partition); } } } else { List <GuidPartitionEntry> entries = GuidPartitionTable.ReadEntriesFromDisk(disk); if (entries != null) { foreach (GuidPartitionEntry entry in entries) { GPTPartition partition = new GPTPartition(entry.PartitionGuid, entry.PartitionTypeGuid, entry.PartitionName, disk, (long)entry.FirstLBA, (long)(entry.SizeLBA * (uint)disk.BytesPerSector)); result.Add(partition); } } } } return(result); }
/// <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); } }
public static void WriteToDisk(Disk disk, MasterBootRecord mbr) { byte[] buffer = mbr.GetBytes(disk.BytesPerSector); disk.WriteSectors(0, buffer); }