예제 #1
0
        /// <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();
                    }
                }
            }
        }