Beispiel #1
0
        /// <summary>
        /// Initialises a new GPT and attempts to read its information from the specified disk.
        /// </summary>
        /// <param name="disk">The disk to read the GPT from.</param>
        public GPT(Hardware.Devices.DiskDevice disk)
        {
#if GPT_TRACE
            BasicConsole.WriteLine("Checking for GPT...");
            BasicConsole.DelayOutput(1);
#endif
            //Assumed block size of 512.
            uint blockSize = 512;

            //Note: The GPT format specifies a protective MBR entry (1 partition 
            //          covering the entire disk) immediately followed (byte-wise)
            //          by the GPT. Thus the GPT must come at 512th byte.
            //      However, some disks can have 4096 bytes per sector (/block) 
            //          so the code below might break as reading LBA 1 (2nd LBA) would
            //          return the wrong data. We probably ought to find some way to 
            //          check the block size and just load the required amount of data.

            //Check for single MBR partition with 0xEE system ID
            byte[] blockData = new byte[blockSize];
            //Read the first sector of data.
            disk.ReadBlock(0UL, 1U, blockData);

            //Attempt to read the MBR
            MBR TheMBR = new MBR(blockData);
            //If the MBR isn't valid, the protective MBR partition specified as part of GPT
            //  isn't present / valid so this isn't a valid GPT.
            if (!TheMBR.IsValid)
            {
#if GPT_TRACE
                BasicConsole.WriteLine("MBR invalid.");
                BasicConsole.DelayOutput(1);
#endif

                return;
            }
            //Or, if there is not one and only one partition in the MBR then the 
            //  protective MBR isn't valid so this isn't a valid GPT
            else if (TheMBR.NumPartitions != 1)
            {
#if GPT_TRACE
                BasicConsole.WriteLine("No partitions in MBR.");
                BasicConsole.DelayOutput(1);
#endif
                return;
            }
            //Or, the first (/only) partition entry has the wrong ID. 0xEE is the partition
            //  ID for a GOT formatted MBR partition.
            else if (TheMBR.Partitions[0].SystemID != 0xEE)
            {
#if GPT_TRACE
                BasicConsole.WriteLine(((FOS_System.String)"MBR partition 0 system ID not GPT. ") + TheMBR.Partitions[0].SystemID);
                BasicConsole.DelayOutput(1);
#endif

                return;
            }

#if GPT_TRACE
            BasicConsole.WriteLine("GPT MBR partition detected.");
            BasicConsole.DelayOutput(1);
#endif

            //Now we know this is very-likely to be GPT formatted. 
            //  But we must check the GPT header for signature etc.

            //Read the GPT block
            disk.ReadBlock(1UL, 1U, blockData);

            //Check for GPT signature: 0x45 0x46 0x49 0x20 0x50 0x41 0x52 0x54
            bool OK = blockData[0] == 0x45;
            OK = OK && blockData[1] == 0x46;
            OK = OK && blockData[2] == 0x49;
            OK = OK && blockData[3] == 0x20;
            OK = OK && blockData[4] == 0x50;
            OK = OK && blockData[5] == 0x41;
            OK = OK && blockData[6] == 0x52;
            OK = OK && blockData[7] == 0x54;

            //If any part of the ID was wrong, this is not a valid GPT.
            if (!OK)
            {
#if GPT_TRACE
                BasicConsole.WriteLine("GPT signature invalid.");
                BasicConsole.DelayOutput(1);
#endif
                return;
            }

            //Now we know, this is a valid GPT. Whether or not the actual entries are valid
            //  is yet to be determined. There is of course the small chance that some other
            //  data has conflicted with GPT data and that this isn't a GPT, it just looks 
            //  like it. If that is the case, what idiot formatted the disk we are reading
            //  because a conflict like that is impossible to detect without user input!
            IsValid = true;
            
#if GPT_TRACE
            BasicConsole.WriteLine("Valid GPT detected.");
            BasicConsole.DelayOutput(5);
#endif

            //Load-in GPT global data
            Revision = ByteConverter.ToUInt32(blockData, 8);
            HeaderSize = ByteConverter.ToUInt32(blockData, 12);
            HeaderCRC32 = ByteConverter.ToUInt32(blockData, 16);
            HeaderLBA = ByteConverter.ToUInt64(blockData, 24);
            HeaderBackupLBA = ByteConverter.ToUInt64(blockData, 32);
            FirstUsableLBAForPartitions = ByteConverter.ToUInt64(blockData, 40);
            LastUsableLBAForPartitions = ByteConverter.ToUInt64(blockData, 48);

#if GPT_TRACE
            BasicConsole.WriteLine(((FOS_System.String)"Revision : ") + Revision);
            BasicConsole.WriteLine(((FOS_System.String)"Header size : ") + HeaderSize);
            BasicConsole.WriteLine(((FOS_System.String)"Header CRC32 : ") + HeaderCRC32);
            BasicConsole.WriteLine(((FOS_System.String)"Header LBA : ") + HeaderLBA);
            BasicConsole.WriteLine(((FOS_System.String)"Header Backup LBA : ") + HeaderBackupLBA);
            BasicConsole.WriteLine(((FOS_System.String)"First usable LBA for partitions : ") + FirstUsableLBAForPartitions);
            BasicConsole.WriteLine(((FOS_System.String)"Last usable LBA for partitions : ") + LastUsableLBAForPartitions);
            BasicConsole.DelayOutput(5);
#endif

            //Load the disk ID
            DiskGUID = new byte[16];
            DiskGUID[0] = blockData[56];
            DiskGUID[1] = blockData[57];
            DiskGUID[2] = blockData[58];
            DiskGUID[3] = blockData[59];
            DiskGUID[4] = blockData[60];
            DiskGUID[5] = blockData[61];
            DiskGUID[6] = blockData[62];
            DiskGUID[7] = blockData[63];
            DiskGUID[8] = blockData[64];
            DiskGUID[9] = blockData[65];
            DiskGUID[10] = blockData[66];
            DiskGUID[11] = blockData[67];
            DiskGUID[12] = blockData[68];
            DiskGUID[13] = blockData[69];
            DiskGUID[14] = blockData[70];
            DiskGUID[15] = blockData[71];

            //Load more global GPT data
            StartingLBAOfPartitionArray = ByteConverter.ToUInt64(blockData, 72);
            NumPartitionEntries = ByteConverter.ToUInt32(blockData, 80);
            SizeOfPartitionEntry = ByteConverter.ToUInt32(blockData, 84);
            PartitionArrayCRC32 = ByteConverter.ToUInt32(blockData, 88);

#if GPT_TRACE
            BasicConsole.WriteLine(((FOS_System.String)"Start LBA of part arrray : ") + StartingLBAOfPartitionArray);
            BasicConsole.WriteLine(((FOS_System.String)"Num part entries : ") + NumPartitionEntries);
            BasicConsole.WriteLine(((FOS_System.String)"Size of part entry : ") + SizeOfPartitionEntry);
            BasicConsole.WriteLine(((FOS_System.String)"Part array CRC32 : ") + PartitionArrayCRC32);
            BasicConsole.DelayOutput(5);
#endif

            ulong blockNum = StartingLBAOfPartitionArray;
            uint entriesPerBlock = blockSize / SizeOfPartitionEntry;

#if GPT_TRACE
            BasicConsole.WriteLine("Reading partition entries...");
            BasicConsole.WriteLine(((FOS_System.String)"blockNum=") + blockNum);
            BasicConsole.WriteLine(((FOS_System.String)"entriesPerBlock=") + entriesPerBlock);
            BasicConsole.DelayOutput(1);
#endif

            //TODO: Check the CRC32 values of the header and partition table
            //      are correct. 
            //Note: By not checking the CRCs, we have the option to manually edit
            //      the GPT without rejecting it if CRCs end up incorrect.
            //TODO: Add an override option to ignore the CRCs
            //TODO: Add a method to update / correct the CRCs

            //Read partition infos
            for(uint i = 0; i < NumPartitionEntries; i++)
            {
                //If we're on a block boundary, we need to load the next block
                //  of data to parse.
                if (i % entriesPerBlock == 0)
                {
#if GPT_TRACE
                    BasicConsole.WriteLine("Reading block data...");
                    BasicConsole.WriteLine(((FOS_System.String)"blockNum=") + blockNum);
                    BasicConsole.DelayOutput(1);
#endif
                    //Load the next block of data
                    disk.ReadBlock(blockNum++, 1u, blockData);
                }

                //Calculate the offset into the current data block
                uint offset = (i % entriesPerBlock) * SizeOfPartitionEntry;
#if GPT_TRACE
                BasicConsole.WriteLine("Reading entry...");
                BasicConsole.WriteLine(((FOS_System.String)"offset=") + offset);
#endif
                //Attempt to load the partition info
                PartitionInfo inf = new PartitionInfo(blockData, offset, SizeOfPartitionEntry);
                //Partitions are marked as empty by an all-zero type ID. If the partition is empty,
                //  there is no point adding it.
                if (!inf.Empty)
                {
#if GPT_TRACE
                    BasicConsole.WriteLine("Entry not empty.");
#endif
                    //Add the non-empty partition
                    Partitions.Add(inf);
                }
#if GPT_TRACE
                else
                {
                    BasicConsole.WriteLine("Entry empty.");
                }
#endif   
            }
        }
Beispiel #2
0
        /// <summary>
        /// Attempts to initialise a disk treating it as MBR formatted.
        /// </summary>
        /// <param name="aDiskDevice">The disk to initialise.</param>
        /// <returns>True if a valid MBR was detected and the disk was successfully initialised. Otherwise, false.</returns>
        private static bool InitAsMBR(DiskDevice aDiskDevice)
        {
#if FSM_TRACE
            BasicConsole.WriteLine("Attempting to read MBR...");
#endif
            byte[] MBRData = new byte[512];
            aDiskDevice.ReadBlock(0UL, 1U, MBRData);
#if FSM_TRACE
            BasicConsole.WriteLine("Read potential MBR data. Attempting to init MBR...");
#endif
            MBR TheMBR = new MBR(MBRData);

            if (!TheMBR.IsValid)
            {
                return false;
            }
            else
            {
#if FSM_TRACE
                BasicConsole.WriteLine("Valid MBR found.");
#endif
                ProcessMBR(TheMBR, aDiskDevice);

                return true;
            }
        }
Beispiel #3
0
 /// <summary>
 /// Processes a valid master boot record to initialize its partitions.
 /// </summary>
 /// <param name="anMBR">The MBR to process.</param>
 /// <param name="aDiskDevice">The disk device from which the MBR was read.</param>
 private static void ProcessMBR(MBR anMBR, DiskDevice aDiskDevice)
 {
     for (int i = 0; i < anMBR.NumPartitions; i++)
     {
         MBR.PartitionInfo aPartInfo = anMBR.Partitions[i];
         if (aPartInfo.EBRLocation != 0)
         {
             byte[] EBRData = new byte[512];
             aDiskDevice.ReadBlock(aPartInfo.EBRLocation, 1U, EBRData);
             EBR newEBR = new EBR(EBRData);
             ProcessMBR(newEBR, aDiskDevice);
         }
         else
         {
             Partitions.Add(new Partition(aDiskDevice, aPartInfo.StartSector, aPartInfo.SectorCount));
         }
     }
 }
Beispiel #4
0
        /// <summary>
        /// Initialises a new GPT and attempts to read its information from the specified disk.
        /// </summary>
        /// <param name="disk">The disk to read the GPT from.</param>
        public GPT(Hardware.Devices.DiskDevice disk)
        {
#if GPT_TRACE
            BasicConsole.WriteLine("Checking for GPT...");
            BasicConsole.DelayOutput(1);
#endif
            //Assumed block size of 512.
            uint blockSize = 512;

            //Note: The GPT format specifies a protective MBR entry (1 partition
            //          covering the entire disk) immediately followed (byte-wise)
            //          by the GPT. Thus the GPT must come at 512th byte.
            //      However, some disks can have 4096 bytes per sector (/block)
            //          so the code below might break as reading LBA 1 (2nd LBA) would
            //          return the wrong data. We probably ought to find some way to
            //          check the block size and just load the required amount of data.

            //Check for single MBR partition with 0xEE system ID
            byte[] blockData = new byte[blockSize];
            //Read the first sector of data.
            disk.ReadBlock(0UL, 1U, blockData);

            //Attempt to read the MBR
            MBR TheMBR = new MBR(blockData);
            //If the MBR isn't valid, the protective MBR partition specified as part of GPT
            //  isn't present / valid so this isn't a valid GPT.
            if (!TheMBR.IsValid)
            {
#if GPT_TRACE
                BasicConsole.WriteLine("MBR invalid.");
                BasicConsole.DelayOutput(1);
#endif

                return;
            }
            //Or, if there is not one and only one partition in the MBR then the
            //  protective MBR isn't valid so this isn't a valid GPT
            else if (TheMBR.NumPartitions != 1)
            {
#if GPT_TRACE
                BasicConsole.WriteLine("No partitions in MBR.");
                BasicConsole.DelayOutput(1);
#endif
                return;
            }
            //Or, the first (/only) partition entry has the wrong ID. 0xEE is the partition
            //  ID for a GOT formatted MBR partition.
            else if (TheMBR.Partitions[0].SystemID != 0xEE)
            {
#if GPT_TRACE
                BasicConsole.WriteLine(((FOS_System.String) "MBR partition 0 system ID not GPT. ") + TheMBR.Partitions[0].SystemID);
                BasicConsole.DelayOutput(1);
#endif

                return;
            }

#if GPT_TRACE
            BasicConsole.WriteLine("GPT MBR partition detected.");
            BasicConsole.DelayOutput(1);
#endif

            //Now we know this is very-likely to be GPT formatted.
            //  But we must check the GPT header for signature etc.

            //Read the GPT block
            disk.ReadBlock(1UL, 1U, blockData);

            //Check for GPT signature: 0x45 0x46 0x49 0x20 0x50 0x41 0x52 0x54
            bool OK = blockData[0] == 0x45;
            OK = OK && blockData[1] == 0x46;
            OK = OK && blockData[2] == 0x49;
            OK = OK && blockData[3] == 0x20;
            OK = OK && blockData[4] == 0x50;
            OK = OK && blockData[5] == 0x41;
            OK = OK && blockData[6] == 0x52;
            OK = OK && blockData[7] == 0x54;

            //If any part of the ID was wrong, this is not a valid GPT.
            if (!OK)
            {
#if GPT_TRACE
                BasicConsole.WriteLine("GPT signature invalid.");
                BasicConsole.DelayOutput(1);
#endif
                return;
            }

            //Now we know, this is a valid GPT. Whether or not the actual entries are valid
            //  is yet to be determined. There is of course the small chance that some other
            //  data has conflicted with GPT data and that this isn't a GPT, it just looks
            //  like it. If that is the case, what idiot formatted the disk we are reading
            //  because a conflict like that is impossible to detect without user input!
            IsValid = true;

#if GPT_TRACE
            BasicConsole.WriteLine("Valid GPT detected.");
            BasicConsole.DelayOutput(5);
#endif

            //Load-in GPT global data
            Revision                    = ByteConverter.ToUInt32(blockData, 8);
            HeaderSize                  = ByteConverter.ToUInt32(blockData, 12);
            HeaderCRC32                 = ByteConverter.ToUInt32(blockData, 16);
            HeaderLBA                   = ByteConverter.ToUInt64(blockData, 24);
            HeaderBackupLBA             = ByteConverter.ToUInt64(blockData, 32);
            FirstUsableLBAForPartitions = ByteConverter.ToUInt64(blockData, 40);
            LastUsableLBAForPartitions  = ByteConverter.ToUInt64(blockData, 48);

#if GPT_TRACE
            BasicConsole.WriteLine(((FOS_System.String) "Revision : ") + Revision);
            BasicConsole.WriteLine(((FOS_System.String) "Header size : ") + HeaderSize);
            BasicConsole.WriteLine(((FOS_System.String) "Header CRC32 : ") + HeaderCRC32);
            BasicConsole.WriteLine(((FOS_System.String) "Header LBA : ") + HeaderLBA);
            BasicConsole.WriteLine(((FOS_System.String) "Header Backup LBA : ") + HeaderBackupLBA);
            BasicConsole.WriteLine(((FOS_System.String) "First usable LBA for partitions : ") + FirstUsableLBAForPartitions);
            BasicConsole.WriteLine(((FOS_System.String) "Last usable LBA for partitions : ") + LastUsableLBAForPartitions);
            BasicConsole.DelayOutput(5);
#endif

            //Load the disk ID
            DiskGUID     = new byte[16];
            DiskGUID[0]  = blockData[56];
            DiskGUID[1]  = blockData[57];
            DiskGUID[2]  = blockData[58];
            DiskGUID[3]  = blockData[59];
            DiskGUID[4]  = blockData[60];
            DiskGUID[5]  = blockData[61];
            DiskGUID[6]  = blockData[62];
            DiskGUID[7]  = blockData[63];
            DiskGUID[8]  = blockData[64];
            DiskGUID[9]  = blockData[65];
            DiskGUID[10] = blockData[66];
            DiskGUID[11] = blockData[67];
            DiskGUID[12] = blockData[68];
            DiskGUID[13] = blockData[69];
            DiskGUID[14] = blockData[70];
            DiskGUID[15] = blockData[71];

            //Load more global GPT data
            StartingLBAOfPartitionArray = ByteConverter.ToUInt64(blockData, 72);
            NumPartitionEntries         = ByteConverter.ToUInt32(blockData, 80);
            SizeOfPartitionEntry        = ByteConverter.ToUInt32(blockData, 84);
            PartitionArrayCRC32         = ByteConverter.ToUInt32(blockData, 88);

#if GPT_TRACE
            BasicConsole.WriteLine(((FOS_System.String) "Start LBA of part arrray : ") + StartingLBAOfPartitionArray);
            BasicConsole.WriteLine(((FOS_System.String) "Num part entries : ") + NumPartitionEntries);
            BasicConsole.WriteLine(((FOS_System.String) "Size of part entry : ") + SizeOfPartitionEntry);
            BasicConsole.WriteLine(((FOS_System.String) "Part array CRC32 : ") + PartitionArrayCRC32);
            BasicConsole.DelayOutput(5);
#endif

            ulong blockNum        = StartingLBAOfPartitionArray;
            uint  entriesPerBlock = blockSize / SizeOfPartitionEntry;

#if GPT_TRACE
            BasicConsole.WriteLine("Reading partition entries...");
            BasicConsole.WriteLine(((FOS_System.String) "blockNum=") + blockNum);
            BasicConsole.WriteLine(((FOS_System.String) "entriesPerBlock=") + entriesPerBlock);
            BasicConsole.DelayOutput(1);
#endif

            //TODO: Check the CRC32 values of the header and partition table
            //      are correct.
            //Note: By not checking the CRCs, we have the option to manually edit
            //      the GPT without rejecting it if CRCs end up incorrect.
            //TODO: Add an override option to ignore the CRCs
            //TODO: Add a method to update / correct the CRCs

            //Read partition infos
            for (uint i = 0; i < NumPartitionEntries; i++)
            {
                //If we're on a block boundary, we need to load the next block
                //  of data to parse.
                if (i % entriesPerBlock == 0)
                {
#if GPT_TRACE
                    BasicConsole.WriteLine("Reading block data...");
                    BasicConsole.WriteLine(((FOS_System.String) "blockNum=") + blockNum);
                    BasicConsole.DelayOutput(1);
#endif
                    //Load the next block of data
                    disk.ReadBlock(blockNum++, 1u, blockData);
                }

                //Calculate the offset into the current data block
                uint offset = (i % entriesPerBlock) * SizeOfPartitionEntry;
#if GPT_TRACE
                BasicConsole.WriteLine("Reading entry...");
                BasicConsole.WriteLine(((FOS_System.String) "offset=") + offset);
#endif
                //Attempt to load the partition info
                PartitionInfo inf = new PartitionInfo(blockData, offset, SizeOfPartitionEntry);
                //Partitions are marked as empty by an all-zero type ID. If the partition is empty,
                //  there is no point adding it.
                if (!inf.Empty)
                {
#if GPT_TRACE
                    BasicConsole.WriteLine("Entry not empty.");
#endif
                    //Add the non-empty partition
                    Partitions.Add(inf);
                }
#if GPT_TRACE
                else
                {
                    BasicConsole.WriteLine("Entry empty.");
                }
#endif
            }
        }