예제 #1
0
 private bool ReadEntries(GptHeader header)
 {
     _diskData.Position = header.PartitionEntriesLba * _diskGeometry.BytesPerSector;
     _entryBuffer       = Utilities.ReadFully(_diskData, (int)(header.PartitionEntrySize * header.PartitionEntryCount));
     if (header.EntriesCrc != CalcEntriesCrc())
     {
         return(false);
     }
     return(true);
 }
예제 #2
0
        /// <summary>
        /// Creates a new partition table on a disk.
        /// </summary>
        /// <param name="disk">The stream containing the disk data.</param>
        /// <param name="diskGeometry">The geometry of the disk.</param>
        /// <returns>An object to access the newly created partition table.</returns>
        public static GuidPartitionTable Initialize(Stream disk, Geometry diskGeometry)
        {
            // Create the protective MBR partition record.
            BiosPartitionTable pt = BiosPartitionTable.Initialize(disk, diskGeometry);

            pt.CreatePrimaryByCylinder(0, diskGeometry.Cylinders - 1, BiosPartitionTypes.GptProtective, false);

            // Create the GPT headers, and blank-out the entry areas
            const int EntryCount = 128;
            const int EntrySize  = 128;

            int entrySectors = (EntryCount * EntrySize + diskGeometry.BytesPerSector - 1) / diskGeometry.BytesPerSector;

            byte[] entriesBuffer = new byte[EntryCount * EntrySize];

            // Prepare primary header
            GptHeader header = new GptHeader(diskGeometry.BytesPerSector);

            header.HeaderLba           = 1;
            header.AlternateHeaderLba  = disk.Length / diskGeometry.BytesPerSector - 1;
            header.FirstUsable         = header.HeaderLba + entrySectors + 1;
            header.LastUsable          = header.AlternateHeaderLba - entrySectors - 1;
            header.DiskGuid            = Guid.NewGuid();
            header.PartitionEntriesLba = 2;
            header.PartitionEntryCount = EntryCount;
            header.PartitionEntrySize  = EntrySize;
            header.EntriesCrc          = CalcEntriesCrc(entriesBuffer);

            // Write the primary header
            byte[] headerBuffer = new byte[diskGeometry.BytesPerSector];
            header.WriteTo(headerBuffer, 0);
            disk.Position = header.HeaderLba * diskGeometry.BytesPerSector;
            disk.Write(headerBuffer, 0, headerBuffer.Length);

            // Write the primary partition table
            disk.Position = header.PartitionEntriesLba * diskGeometry.BytesPerSector;
            disk.Write(entriesBuffer, 0, entriesBuffer.Length);

            // Calc alternate header
            header.HeaderLba           = header.AlternateHeaderLba;
            header.AlternateHeaderLba  = 1;
            header.PartitionEntriesLba = header.HeaderLba - entrySectors;

            // Write the alternate header
            header.WriteTo(headerBuffer, 0);
            disk.Position = header.HeaderLba * diskGeometry.BytesPerSector;
            disk.Write(headerBuffer, 0, headerBuffer.Length);

            // Write the alternate partition table
            disk.Position = header.PartitionEntriesLba * diskGeometry.BytesPerSector;
            disk.Write(entriesBuffer, 0, entriesBuffer.Length);

            return(new GuidPartitionTable(disk, diskGeometry));
        }
예제 #3
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));
        }
예제 #4
0
        public GptHeader(GptHeader toCopy)
        {
            Signature           = toCopy.Signature;
            Version             = toCopy.Version;
            HeaderSize          = toCopy.HeaderSize;
            Crc                 = toCopy.Crc;
            HeaderLba           = toCopy.HeaderLba;
            AlternateHeaderLba  = toCopy.AlternateHeaderLba;
            FirstUsable         = toCopy.FirstUsable;
            LastUsable          = toCopy.LastUsable;
            DiskGuid            = toCopy.DiskGuid;
            PartitionEntriesLba = toCopy.PartitionEntriesLba;
            PartitionEntryCount = toCopy.PartitionEntryCount;
            PartitionEntrySize  = toCopy.PartitionEntrySize;
            EntriesCrc          = toCopy.EntriesCrc;

            Buffer = new byte[toCopy.Buffer.Length];
            Array.Copy(toCopy.Buffer, Buffer, Buffer.Length);
        }
예제 #5
0
        public GptHeader(GptHeader toCopy)
        {
            Signature = toCopy.Signature;
            Version = toCopy.Version;
            HeaderSize = toCopy.HeaderSize;
            Crc = toCopy.Crc;
            HeaderLba = toCopy.HeaderLba;
            AlternateHeaderLba = toCopy.AlternateHeaderLba;
            FirstUsable = toCopy.FirstUsable;
            LastUsable = toCopy.LastUsable;
            DiskGuid = toCopy.DiskGuid;
            PartitionEntriesLba = toCopy.PartitionEntriesLba;
            PartitionEntryCount = toCopy.PartitionEntryCount;
            PartitionEntrySize = toCopy.PartitionEntrySize;
            EntriesCrc = toCopy.EntriesCrc;

            Buffer = new byte[toCopy.Buffer.Length];
            Array.Copy(toCopy.Buffer, Buffer, Buffer.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();
                    }
                }
            }
        }