private int GetPartitionOffset(int index) { bool found = false; int entriesSoFar = 0; int position = 0; while (!found && position < _primaryHeader.PartitionEntryCount) { GptEntry entry = new GptEntry(); entry.ReadFrom(_entryBuffer, position * _primaryHeader.PartitionEntrySize); if (entry.PartitionType != Guid.Empty) { if (index == entriesSoFar) { found = true; break; } entriesSoFar++; } position++; } if (found) { return(position * _primaryHeader.PartitionEntrySize); } throw new IOException(string.Format(CultureInfo.InvariantCulture, "No such partition: {0}", index)); }
internal SparseStream Open(GptEntry entry) { long start = entry.FirstUsedLogicalBlock * _diskGeometry.BytesPerSector; long end = (entry.LastUsedLogicalBlock + 1) * _diskGeometry.BytesPerSector; return(new SubStream(_diskData, start, end - start)); }
private void EstablishReservedPartition(List <GptEntry> allEntries) { // If no MicrosoftReserved partition, and no Microsoft Data partitions, and the disk // has a 'reasonable' size free, create a Microsoft Reserved partition. if (CountEntries(allEntries, e => e.PartitionType == GuidPartitionTypes.MicrosoftReserved) == 0 && CountEntries(allEntries, e => e.PartitionType == GuidPartitionTypes.WindowsBasicData) == 0 && _diskGeometry.Capacity > 512 * 1024 * 1024) { long reservedStart = FirstAvailableSector(allEntries); long reservedEnd = FindLastFreeSector(reservedStart, allEntries); if ((reservedEnd - reservedStart + 1) * _diskGeometry.BytesPerSector > 512 * 1024 * 1024) { long size = (_diskGeometry.Capacity < 16 * 1024L * 1024 * 1024 ? 32 : 128) * 1024 * 1024; reservedEnd = reservedStart + size / _diskGeometry.BytesPerSector - 1; int reservedOffset = GetFreeEntryOffset(); GptEntry newReservedEntry = new GptEntry(); newReservedEntry.PartitionType = GuidPartitionTypes.MicrosoftReserved; newReservedEntry.Identity = Guid.NewGuid(); newReservedEntry.FirstUsedLogicalBlock = reservedStart; newReservedEntry.LastUsedLogicalBlock = reservedEnd; newReservedEntry.Attributes = 0; newReservedEntry.Name = "Microsoft reserved partition"; newReservedEntry.WriteTo(_entryBuffer, reservedOffset); allEntries.Add(newReservedEntry); } } }
private IEnumerable <GptEntry> GetAllEntries() { for (int i = 0; i < _primaryHeader.PartitionEntryCount; ++i) { GptEntry entry = new GptEntry(); entry.ReadFrom(_entryBuffer, i * _primaryHeader.PartitionEntrySize); if (entry.PartitionType != Guid.Empty) { yield return(entry); } } }
/// <summary> /// Creates a new partition that encompasses the entire disk. /// </summary> /// <param name="type">The partition type</param> /// <param name="active">Whether the partition is active (bootable)</param> /// <returns>The index of the partition</returns> /// <remarks>The partition table must be empty before this method is called, /// otherwise IOException is thrown.</remarks> public override int Create(WellKnownPartitionType type, bool active) { List <GptEntry> allEntries = new List <GptEntry>(GetAllEntries()); // If no MicrosoftReserved partition, and no Microsoft Data partitions, and the disk // has a 'reasonable' size free, create a Microsoft Reserved partition. if (CountEntries(allEntries, e => e.PartitionType == GuidPartitionTypes.MicrosoftReserved) == 0 && CountEntries(allEntries, e => e.PartitionType == GuidPartitionTypes.WindowsBasicData) == 0 && _diskGeometry.Capacity > 512 * 1024 * 1024) { long reservedStart = FirstAvailableSector(allEntries); long reservedEnd = FindLastFreeSector(reservedStart, allEntries); if ((reservedEnd - reservedStart + 1) * _diskGeometry.BytesPerSector > 512 * 1024 * 1024) { long size = ((_diskGeometry.Capacity < (16 * 1024L * 1024 * 1024)) ? 32 : 128) * 1024 * 1024; reservedEnd = reservedStart + (size / _diskGeometry.BytesPerSector) - 1; int reservedOffset = GetFreeEntryOffset(); GptEntry newReservedEntry = new GptEntry(); newReservedEntry.PartitionType = GuidPartitionTypes.MicrosoftReserved; newReservedEntry.Identity = Guid.NewGuid(); newReservedEntry.FirstUsedLogicalBlock = reservedStart; newReservedEntry.LastUsedLogicalBlock = reservedEnd; newReservedEntry.Attributes = 0; newReservedEntry.Name = "Microsoft reserved partition"; newReservedEntry.WriteTo(_entryBuffer, reservedOffset); allEntries.Add(newReservedEntry); } } // Fill the rest of the disk with the requested partition long start = FirstAvailableSector(allEntries); long end = FindLastFreeSector(start, allEntries); int offset = GetFreeEntryOffset(); GptEntry newEntry = new GptEntry(); newEntry.PartitionType = GuidPartitionTypes.Convert(type); newEntry.Identity = Guid.NewGuid(); newEntry.FirstUsedLogicalBlock = start; newEntry.LastUsedLogicalBlock = end; newEntry.Attributes = 0; newEntry.Name = "Data Partition"; newEntry.WriteTo(_entryBuffer, offset); // Commit changes to disk Write(); return(GetEntryIndex(newEntry.Identity)); }
private int GetFreeEntryOffset() { for (int i = 0; i < _primaryHeader.PartitionEntryCount; ++i) { GptEntry entry = new GptEntry(); entry.ReadFrom(_entryBuffer, i * _primaryHeader.PartitionEntrySize); if (entry.PartitionType == Guid.Empty) { return(i * _primaryHeader.PartitionEntrySize); } } throw new IOException("No free partition entries available"); }
/// <summary> /// Makes a best guess at the geometry of a disk. /// </summary> /// <param name="disk">String containing the disk image to detect the geometry from.</param> /// <returns>The detected geometry.</returns> public static Geometry DetectGeometry(Stream disk) { if (disk.Length >= Sizes.Sector) { disk.Position = 0; byte[] bootSector = StreamUtilities.ReadExact(disk, Sizes.Sector); if (bootSector[510] == 0x55 && bootSector[511] == 0xAA) { long lastSector = 0; disk.Position = Sizes.Sector; var sector = StreamUtilities.ReadExact(disk, Sizes.Sector); var header = new GptHeader(Sizes.Sector); if (!header.ReadFrom(sector, 0)) { throw new InvalidDataException("Failed to read primary GPT header"); } disk.Position = header.PartitionEntriesLba * Sizes.Sector; var entryBuffer = StreamUtilities.ReadExact(disk, (int)(header.PartitionEntrySize * header.PartitionEntryCount)); if (header.EntriesCrc != Crc32LittleEndian.Compute(Crc32Algorithm.Common, entryBuffer, 0, entryBuffer.Length)) { throw new InvalidDataException("Invalid GPT header"); } for (int i = 0; i < header.PartitionEntryCount; ++i) { GptEntry entry = new GptEntry(); entry.ReadFrom(entryBuffer, i * header.PartitionEntrySize); if (entry.PartitionType != Guid.Empty) { lastSector = entry.LastUsedLogicalBlock + 1; } } if (lastSector > 0) { return(Geometry.FromCapacity(lastSector * Sizes.Sector, Sizes.Sector)); } } } return(Geometry.FromCapacity(disk.Length)); }
private int GetEntryIndex(Guid identity) { int index = 0; for (int i = 0; i < _primaryHeader.PartitionEntryCount; ++i) { GptEntry entry = new GptEntry(); entry.ReadFrom(_entryBuffer, i * _primaryHeader.PartitionEntrySize); if (entry.Identity == identity) { return(index); } if (entry.PartitionType != Guid.Empty) { index++; } } throw new IOException("No such partition"); }
private GptEntry CreateEntry(long startSector, long endSector, Guid type, long attributes, string name) { if (endSector < startSector) { throw new ArgumentException("The end sector is before the start sector"); } int offset = GetFreeEntryOffset(); GptEntry newEntry = new GptEntry(); newEntry.PartitionType = type; newEntry.Identity = Guid.NewGuid(); newEntry.FirstUsedLogicalBlock = startSector; newEntry.LastUsedLogicalBlock = endSector; newEntry.Attributes = (ulong)attributes; newEntry.Name = name; newEntry.WriteTo(_entryBuffer, offset); // Commit changes to disk Write(); return(newEntry); }
/// <summary> /// Creates a new GUID partition on the disk. /// </summary> /// <param name="startSector">The first sector of the partition.</param> /// <param name="endSector">The last sector of the partition.</param> /// <param name="type">The partition type.</param> /// <param name="attributes">The partition attributes.</param> /// <param name="name">The name of the partition.</param> /// <returns>The index of the new partition.</returns> /// <remarks>No checking is performed on the parameters, the caller is /// responsible for ensuring that the partition does not overlap other partitions.</remarks> public int Create(long startSector, long endSector, Guid type, long attributes, string name) { GptEntry newEntry = CreateEntry(startSector, endSector, type, attributes, name); return(GetEntryIndex(newEntry.Identity)); }
internal SparseStream Open(GptEntry entry) { return(new SubStream(_diskData, entry.FirstUsedLogicalBlock * _diskGeometry.BytesPerSector, entry.LastUsedLogicalBlock * _diskGeometry.BytesPerSector)); }
internal GuidPartitionInfo(GuidPartitionTable table, GptEntry entry) { _table = table; _entry = entry; }