/// <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 void Init(Stream disk, Geometry diskGeometry) { BiosPartitionTable bpt; try { bpt = new BiosPartitionTable(disk, diskGeometry); } catch (IOException ioe) { throw new IOException("Invalid GPT disk, protective MBR table not present or invalid", ioe); } if (bpt.Count != 1 || bpt[0].BiosType != BiosPartitionTypes.GptProtective) { throw new IOException("Invalid GPT disk, protective MBR table is not valid"); } _diskData = disk; _diskGeometry = diskGeometry; disk.Position = diskGeometry.BytesPerSector; byte[] sector = StreamUtilities.ReadFully(disk, diskGeometry.BytesPerSector); _primaryHeader = new GptHeader(diskGeometry.BytesPerSector); if (!_primaryHeader.ReadFrom(sector, 0) || !ReadEntries(_primaryHeader)) { disk.Position = disk.Length - diskGeometry.BytesPerSector; disk.Read(sector, 0, sector.Length); _secondaryHeader = new GptHeader(diskGeometry.BytesPerSector); if (!_secondaryHeader.ReadFrom(sector, 0) || !ReadEntries(_secondaryHeader)) { throw new IOException("No valid GUID Partition Table found"); } // Generate from the primary table from the secondary one _primaryHeader = new GptHeader(_secondaryHeader); _primaryHeader.HeaderLba = _secondaryHeader.AlternateHeaderLba; _primaryHeader.AlternateHeaderLba = _secondaryHeader.HeaderLba; _primaryHeader.PartitionEntriesLba = 2; // If the disk is writeable, fix up the primary partition table based on the // (valid) secondary table. if (disk.CanWrite) { WritePrimaryHeader(); } } if (_secondaryHeader == null) { _secondaryHeader = new GptHeader(diskGeometry.BytesPerSector); disk.Position = disk.Length - diskGeometry.BytesPerSector; disk.Read(sector, 0, sector.Length); if (!_secondaryHeader.ReadFrom(sector, 0) || !ReadEntries(_secondaryHeader)) { // Generate from the secondary table from the primary one _secondaryHeader = new GptHeader(_primaryHeader); _secondaryHeader.HeaderLba = _secondaryHeader.AlternateHeaderLba; _secondaryHeader.AlternateHeaderLba = _secondaryHeader.HeaderLba; _secondaryHeader.PartitionEntriesLba = _secondaryHeader.HeaderLba - MathUtilities.RoundUp( _secondaryHeader.PartitionEntryCount * _secondaryHeader.PartitionEntrySize, diskGeometry.BytesPerSector); // If the disk is writeable, fix up the secondary partition table based on the // (valid) primary table. if (disk.CanWrite) { WriteSecondaryHeader(); } } } }