/// <summary> /// Reads the master boot block. /// </summary> /// <returns></returns> public bool Read() { valid = false; MasterBootBlock mbr = new MasterBootBlock(diskDevice); if (!mbr.Valid) return false; if ((mbr.Partitions[0].PartitionType != PartitionType.GPT) || (mbr.Partitions[1].PartitionType != PartitionType.Empty) || (mbr.Partitions[2].PartitionType != PartitionType.Empty) || (mbr.Partitions[3].PartitionType != PartitionType.Empty) || (!mbr.Partitions[0].Bootable) || (mbr.Partitions[0].StartLBA != 1)) return false; BinaryFormat gpt = new BinaryFormat(diskDevice.ReadBlock(1, 1)); if ((gpt.GetByte(0) != 45) && (gpt.GetByte(1) != 46) && (gpt.GetByte(2) != 49) && (gpt.GetByte(3) != 20) && (gpt.GetByte(4) != 50) && (gpt.GetByte(5) != 41) && (gpt.GetByte(6) != 52) && (gpt.GetByte(7) != 54)) return false; if ((gpt.GetUInt(GPT.Revision) != GPTConstant.SupportedRevision) || (gpt.GetUInt(GPT.HeaderSize) != GPTConstant.HeaderSize) || (gpt.GetUInt(GPT.Reserved) != 0) || (gpt.GetUInt(GPT.PartitionStartingLBA) != 2) ) return false; valid = true; return valid; }
/// <summary> /// Gets the size of the file. /// </summary> /// <param name="directoryBlock">The directory block.</param> /// <param name="index">The index.</param> /// <returns></returns> public uint GetFileSize(uint directoryBlock, uint index) { BinaryFormat directory = new BinaryFormat(partition.ReadBlock(directoryBlock, 1)); return directory.GetUInt((index * Entry.EntrySize) + Entry.FileSize); }
/// <summary> /// Reads the boot sector. /// </summary> /// <returns></returns> protected bool ReadBootSector() { valid = false; if (blockSize != 512) // only going to work with 512 sector sizes (for now) return false; BinaryFormat bootSector = new BinaryFormat(partition.ReadBlock(0, 1)); if (bootSector.GetUShort(BootSector.BootSectorSignature) != 0xAA55) return false; byte extendedBootSignature = bootSector.GetByte(BootSector.ExtendedBootSignature); byte extendedBootSignature32 = bootSector.GetByte(BootSector.FAT32_ExtendedBootSignature); if ((extendedBootSignature != 0x29) && (extendedBootSignature != 0x28) && (extendedBootSignature32 != 0x29)) return false; volumeLabel = bootSector.GetString(BootSector.VolumeLabel, 8).ToString().TrimEnd(); bytesPerSector = bootSector.GetUShort(BootSector.BytesPerSector); sectorsPerCluster = bootSector.GetByte(BootSector.SectorsPerCluster); reservedSectors = bootSector.GetByte(BootSector.ReservedSectors); nbrFats = bootSector.GetByte(BootSector.FatAllocationTables); rootEntries = bootSector.GetUShort(BootSector.MaxRootDirEntries); rootCluster32 = bootSector.GetUInt(BootSector.FAT32_ClusterNumberOfRoot); uint sectorsPerFat16 = bootSector.GetUShort(BootSector.SectorsPerFAT); uint sectorsPerFat32 = bootSector.GetUInt(BootSector.FAT32_SectorPerFAT); uint totalSectors16 = bootSector.GetUShort(BootSector.TotalSectors16); uint totalSectors32 = bootSector.GetUInt(BootSector.TotalSectors32); uint sectorsPerFat = (sectorsPerFat16 != 0) ? sectorsPerFat16 : sectorsPerFat32; uint fatSectors = 0; try { fatSectors = nbrFats * sectorsPerFat; clusterSizeInBytes = sectorsPerCluster * blockSize; rootDirSectors = (((rootEntries * 32) + (bytesPerSector - 1)) / bytesPerSector); firstDataSector = reservedSectors + (nbrFats * sectorsPerFat) + rootDirSectors; totalSectors = (totalSectors16 != 0) ? totalSectors16 : totalSectors32; dataSectors = totalSectors - (reservedSectors + (nbrFats * sectorsPerFat) + rootDirSectors); totalClusters = dataSectors / sectorsPerCluster; entriesPerSector = (bytesPerSector / 32); firstRootDirectorySector = reservedSectors + fatSectors; dataAreaStart = firstRootDirectorySector + rootDirSectors; } catch { return false; } // Some basic checks if ((nbrFats == 0) || (nbrFats > 2) || (totalSectors == 0) || (sectorsPerFat == 0)) return false; if (totalClusters < 4085) fatType = FatType.FAT12; else if (totalClusters < 65525) fatType = FatType.FAT16; else fatType = FatType.FAT32; if (fatType == FatType.FAT12) { reservedClusterMark = 0xFF0; endOfClusterMark = 0x0FF8; badClusterMark = 0x0FF7; fatMask = 0xFFFFFFFF; fatEntries = sectorsPerFat * 3 * blockSize / 2; } else if (fatType == FatType.FAT16) { reservedClusterMark = 0xFFF0; endOfClusterMark = 0xFFF8; badClusterMark = 0xFFF7; fatMask = 0xFFFFFFFF; fatEntries = sectorsPerFat * blockSize / 2; } else { // if (type == FatType.FAT32) { reservedClusterMark = 0xFFF0; endOfClusterMark = 0x0FFFFFF8; badClusterMark = 0x0FFFFFF7; fatMask = 0x0FFFFFFF; fatEntries = sectorsPerFat * blockSize / 4; } // More basic checks if ((fatType == FatType.FAT32) && (rootCluster32 == 0)) return false; valid = true; serialNbr = bootSector.GetBytes(fatType != FatType.FAT32 ? BootSector.IDSerialNumber : BootSector.FAT32_IDSerialNumber, 4); return true; }
/// <summary> /// Gets the cluster entry value. /// </summary> /// <param name="cluster">The cluster.</param> /// <returns></returns> protected uint GetClusterEntryValue(uint cluster) { uint fatoffset = 0; if (fatType == FatType.FAT12) fatoffset = (cluster + (cluster / 2)); else if (fatType == FatType.FAT16) fatoffset = cluster * 2; else //if (type == FatType.FAT32) fatoffset = cluster * 4; uint sector = reservedSectors + (fatoffset / bytesPerSector); uint sectorOffset = fatoffset % bytesPerSector; uint nbrSectors = 1; if ((fatType == FatType.FAT12) && (sectorOffset == bytesPerSector - 1)) nbrSectors = 2; BinaryFormat fat = new BinaryFormat(partition.ReadBlock(sector, nbrSectors)); uint clusterValue; if (fatType == FatType.FAT12) { clusterValue = fat.GetUShort(sectorOffset); if (cluster % 2 == 1) clusterValue = clusterValue >> 4; else clusterValue = clusterValue & 0x0FFF; } else if (fatType == FatType.FAT16) clusterValue = fat.GetUShort(sectorOffset); else //if (type == FatType.FAT32) clusterValue = fat.GetUInt(sectorOffset) & 0x0FFFFFFF; return clusterValue; }
public static void PatchSyslinux_3_72(PartitionDevice partitionDevice, FatFileSystem fat) { // Locate ldlinux.sys file for patching string filename = "ldlinux.sys"; string name = (Path.GetFileNameWithoutExtension(filename) + Path.GetExtension(filename).PadRight(4).Substring(0, 4)).ToUpper(); var location = fat.FindEntry(new Mosa.FileSystem.FAT.Find.WithName(name), 0); if (location.IsValid) { // Read boot sector var bootSector = new BinaryFormat(partitionDevice.ReadBlock(0, 1)); // Set the first sector location of the file bootSector.SetUInt(0x1F8, fat.GetSectorByCluster(location.FirstCluster)); // Change jump address bootSector.SetUInt(0x01, 0x58); // Write back patched boot sector partitionDevice.WriteBlock(0, 1, bootSector.Data); // Get the file size & number of sectors used uint fileSize = fat.GetFileSize(location.DirectorySector, location.DirectorySectorIndex); uint sectorCount = (fileSize + 511) >> 9; uint[] sectors = new uint[65]; uint nsec = 0; // Create list of the first 65 sectors of the file for (uint cluster = location.FirstCluster; ((cluster != 0) & (nsec <= 64)); cluster = fat.GetNextCluster(cluster)) { uint sec = fat.GetSectorByCluster(cluster); for (uint s = 0; s < fat.SectorsPerCluster; s++) sectors[nsec++] = sec + s; } // Read the first cluster of the file var firstCluster = new BinaryFormat(fat.ReadCluster(location.FirstCluster)); uint patchArea = 0; // Search for 0x3EB202FE (magic) for (patchArea = 0; (firstCluster.GetUInt(patchArea) != 0x3EB202FE) && (patchArea < fat.ClusterSizeInBytes); patchArea += 4) ; patchArea = patchArea + 8; if (patchArea < fat.ClusterSizeInBytes) { // Set up the totals firstCluster.SetUShort(patchArea, (ushort)(fileSize >> 2)); firstCluster.SetUShort(patchArea + 2, (ushort)(sectorCount - 1)); // Clear sector entries firstCluster.Fill(patchArea + 8, 0, 64 * 4); // Set sector entries for (nsec = 0; nsec < 64; nsec++) firstCluster.SetUInt(patchArea + 8 + (nsec * 4), sectors[nsec + 1]); // Clear out checksum firstCluster.SetUInt(patchArea + 4, 0); // Write back the updated cluster fat.WriteCluster(location.FirstCluster, firstCluster.Data); // Re-Calculate checksum by opening the file var file = new FatFileStream(fat, location); uint csum = 0x3EB202FE; for (uint index = 0; index < (file.Length >> 2); index++) { uint value = (uint)file.ReadByte() | ((uint)file.ReadByte() << 8) | ((uint)file.ReadByte() << 16) | ((uint)file.ReadByte() << 24); csum -= value; } // Set the checksum firstCluster.SetUInt(patchArea + 4, csum); // Write patched cluster back to disk fat.WriteCluster(location.FirstCluster, firstCluster.Data); } } }
/// <summary> /// Opens the specified drive NBR. /// </summary> /// <param name="drive">The drive NBR.</param> /// <returns></returns> public bool Open(uint drive) { if (drive > MaximunDriveCount) return false; if (!driveInfo[drive].Present) return false; if (drive == 0) DeviceHeadPort.Write8(0xA0); else if (drive == 1) DeviceHeadPort.Write8(0xB0); else return false; CommandPort.Write8(IDECommands.IdentifyDrive); if (!WaitForRegisterReady()) return false; var info = new BinaryFormat(new byte[512]); for (uint index = 0; index < 256; index++) info.SetUShort(index * 2, DataPort.Read16()); driveInfo[drive].MaxLBA = info.GetUInt(IdentifyDrive.MaxLBA28); return true; }
/// <summary> /// Reads the master boot block. /// </summary> /// <returns></returns> public bool Read() { valid = false; if (diskDevice.BlockSize != 512) return false; // only going to work with 512 sector sizes if (diskDevice.TotalBlocks < 3) return false; BinaryFormat masterboot = new BinaryFormat(diskDevice.ReadBlock(0, 1)); if (masterboot.GetUShort(MBR.MBRSignature) != MBRConstant.MBRSignature) return false; valid = true; diskSignature = masterboot.GetUInt(MBR.DiskSignature); for (uint index = 0; index < MaxMBRPartitions; index++) { uint offset = MBR.FirstPartition + (index * MBRConstant.PartitionSize); GenericPartition partition = new GenericPartition(index); partition.Bootable = masterboot.GetByte(offset + PartitionRecord.Status) == MBRConstant.Bootable; partition.PartitionType = masterboot.GetByte(offset + PartitionRecord.PartitionType); partition.StartLBA = masterboot.GetUInt(offset + PartitionRecord.LBA); partition.TotalBlocks = masterboot.GetUInt(offset + PartitionRecord.Sectors); Partitions[index] = partition; } //TODO: Extended Partitions code = new byte[MBRConstant.CodeAreaSize]; for (uint index = 0; index < MBRConstant.CodeAreaSize; index++) code[index] = masterboot.GetByte(index); return valid; }