/// <summary> /// Creates a new FAT32 partition that covers the entire drive. /// </summary> /// <param name="aDisk">The disk to create the partition for.</param> /// <param name="bootable">Whether to mark the partition as bootable or not.</param> /// <returns>The new partition information.</returns> public static PartitionInfo CreateFAT32PartitionInfo(Hardware.Devices.DiskDevice aDisk, bool bootable) { //Can't remember why but we have to start at 3rd logical block // - First sector (sector 0) is for the MBR // - Why do we leave a second sector empty after it? return(new PartitionInfo(bootable, 0xC, 2U, (uint)(aDisk.BlockCount - 2))); }
public VolumeDescriptor(Hardware.Devices.DiskDevice disk, uint startBlock, uint numBlocks, byte[] data) : base(disk, 0, 0) { Code = (TypeCodes)data[0]; Id = ByteConverter.GetASCIIStringFromASCII(data, 1, 5); Version = data[6]; }
public PrimaryVolumeDescriptor(Hardware.Devices.DiskDevice disk, uint startBlock, uint numBlocks, byte[] data) : base(disk, startBlock, numBlocks, data) { SystemIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 8, 32); VolumeIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 40, 32); VolumeSpaceSize = ByteConverter.ToUInt32(data, 80); VolumeSetSize = ByteConverter.ToUInt16(data, 120); VolumeSequenceNumber = ByteConverter.ToUInt16(data, 124); LogicalBlockSize = ByteConverter.ToUInt16(data, 128); PathTableSize = ByteConverter.ToUInt32(data, 132); Location_PathTable_TypeL = ByteConverter.ToUInt32(data, 140); Location_PathTable_Optional_TypeL = ByteConverter.ToUInt32(data, 144); RootDirectory = new DirectoryRecord(data, 156, true); VolumeSetIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 190, 128); PublisherIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 318, 128); DataPreparerIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 446, 128); ApplicationIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 574, 128); CopyrightFileIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 702, 38); AbstractFileIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 740, 36); BibliographicFileIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 776, 37); VolumeCreationDateTime = new DateTime(data, 813); VolumeModificationDateTime = new DateTime(data, 830); VolumeExpirationDateTime = new DateTime(data, 847); VolumeEffectiveDateTime = new DateTime(data, 864); FileStructureVersion = data[881]; }
public ISO9660(Hardware.Devices.DiskDevice disk) { byte[] data = disk.NewBlockArray(1); VolumeDescriptor desciptor = null; uint sector = 0x10; do { disk.ReadBlock(sector, 1, data); desciptor = VolumeDescriptor.CreateDescriptor(disk, sector, 1); VolumeDescriptors.Add(desciptor); sector++; }while (desciptor.Code != VolumeDescriptor.TypeCodes.SetTerminator); }
public static VolumeDescriptor CreateDescriptor(Hardware.Devices.DiskDevice disk, uint startBlock, uint numBlocks) { byte[] data = disk.NewBlockArray(numBlocks); disk.ReadBlock(startBlock, numBlocks, data); switch ((TypeCodes)data[0]) { case TypeCodes.BootRecord: return(new BootRecord(disk, startBlock, numBlocks, data)); case TypeCodes.Primary: return(new PrimaryVolumeDescriptor(disk, startBlock, numBlocks, data)); case TypeCodes.SetTerminator: return(new SetTerminatorVolumeDescriptor(disk, startBlock, numBlocks, data)); default: return(new VolumeDescriptor(disk, startBlock, numBlocks, data)); } }
/// <summary> /// Formats the specified using the specified partition informations. /// </summary> /// <param name="aDisk">The disk to format.</param> /// <param name="partitionInfos">The partition informations to use for the format.</param> public static void FormatDisk(Hardware.Devices.DiskDevice aDisk, List partitionInfos) { //Necessary to remove any trace of GPT: // Overwrite first 256 sectors with 0s (should do the trick) aDisk.WriteBlock(0UL, 256U, null); #if MBR_TRACE BasicConsole.WriteLine("Creating new MBR data..."); #endif byte[] newMBRData = new byte[512]; newMBRData[0x1FE] = 0x55; newMBRData[0x1FF] = 0xAA; #if MBR_TRACE BasicConsole.WriteLine(((FOS_System.String) "Set signature: ") + newMBRData[0x1FE] + " " + newMBRData[0x1FF]); BasicConsole.DelayOutput(1); BasicConsole.WriteLine(((FOS_System.String) "Num new partitions: ") + partitionInfos.Count); BasicConsole.DelayOutput(1); #endif uint part1Offset = 0x1BE; for (uint i = 0; i < partitionInfos.Count; i++) { PartitionInfo partInfo = (PartitionInfo)partitionInfos[(int)i]; uint partOffset = part1Offset + (0x10 * i); #if MBR_TRACE BasicConsole.WriteLine(((FOS_System.String) "Partition ") + i + " @ " + partOffset); BasicConsole.WriteLine(((FOS_System.String) "Bootable : ") + partInfo.Bootable); BasicConsole.WriteLine(((FOS_System.String) "SystemID : ") + partInfo.SystemID); BasicConsole.WriteLine(((FOS_System.String) "StartSector : ") + partInfo.StartSector); BasicConsole.WriteLine(((FOS_System.String) "SectorCount : ") + partInfo.SectorCount); BasicConsole.DelayOutput(2); #endif //Bootable / active newMBRData[partOffset + 0] = (byte)(partInfo.Bootable ? 0x81 : 0x00); //System ID newMBRData[partOffset + 4] = partInfo.SystemID; //Start sector newMBRData[partOffset + 8] = (byte)(partInfo.StartSector); newMBRData[partOffset + 9] = (byte)(partInfo.StartSector >> 8); newMBRData[partOffset + 10] = (byte)(partInfo.StartSector >> 16); newMBRData[partOffset + 11] = (byte)(partInfo.StartSector >> 24); //Sector count newMBRData[partOffset + 12] = (byte)(partInfo.SectorCount); newMBRData[partOffset + 13] = (byte)(partInfo.SectorCount >> 8); newMBRData[partOffset + 14] = (byte)(partInfo.SectorCount >> 16); newMBRData[partOffset + 15] = (byte)(partInfo.SectorCount >> 24); #if MBR_TRACE BasicConsole.WriteLine("Reading back data..."); byte bootable = newMBRData[partOffset + 0]; byte systemID = newMBRData[partOffset + 4]; UInt32 startSector = ByteConverter.ToUInt32(newMBRData, partOffset + 8); UInt32 sectorCount = ByteConverter.ToUInt32(newMBRData, partOffset + 12); BasicConsole.WriteLine(((FOS_System.String) "Bootable : ") + bootable); BasicConsole.WriteLine(((FOS_System.String) "SystemID : ") + systemID); BasicConsole.WriteLine(((FOS_System.String) "StartSector : ") + startSector); BasicConsole.WriteLine(((FOS_System.String) "SectorCount : ") + sectorCount); BasicConsole.DelayOutput(2); #endif } #if MBR_TRACE BasicConsole.WriteLine("Writing data..."); #endif aDisk.WriteBlock(0UL, 1U, newMBRData); #if MBR_TRACE BasicConsole.WriteLine("Data written."); BasicConsole.DelayOutput(1); #endif aDisk.CleanCaches(); }
/// <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 } }
public SetTerminatorVolumeDescriptor(Hardware.Devices.DiskDevice disk, uint startBlock, uint numBlocks, byte[] data) : base(disk, startBlock, numBlocks, data) { }
public BootRecord(Hardware.Devices.DiskDevice disk, uint startBlock, uint numBlocks, byte[] data) : base(disk, startBlock, numBlocks, data) { BootSystemIdentifier = ByteConverter.GetASCIIStringFromASCII(data, 7, 32); BootSystem = ByteConverter.GetASCIIStringFromASCII(data, 39, 32); }