/// <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> /// Compares the specified data. /// </summary> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <param name="type">The type.</param> /// <returns></returns> public bool Compare(byte[] data, uint offset, FatType type) { BinaryFormat entry = new BinaryFormat(data); byte first = entry.GetByte(offset + Entry.DOSName); if (first == FileNameAttribute.LastEntry) return true; if ((first == FileNameAttribute.Deleted) | (first == FileNameAttribute.Dot)) return true; return false; }
/// <summary> /// Compares the specified data. /// </summary> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <param name="type">The type.</param> /// <returns></returns> public bool Compare(byte[] data, uint offset, FatType type) { var entry = new BinaryFormat(data); byte first = entry.GetByte(offset + Entry.DOSName); if (first == FileNameAttribute.LastEntry) return false; if ((first == FileNameAttribute.Deleted) | (first == FileNameAttribute.Dot)) return false; if (first == FileNameAttribute.Escape) return false; string entryname = FatFileSystem.ExtractFileName(data, offset); if (entryname == name) return true; return false; }
return false; if ((first == FileNameAttribute.Deleted) | (first == FileNameAttribute.Dot)) return false; if (first == FileNameAttribute.Escape) return false; uint startcluster = FatFileSystem.GetClusterEntry(data, offset, type); if (startcluster == cluster) return true; return false; } } }
/// <summary> /// Compares the specified data. /// </summary> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <param name="type">The type.</param> /// <returns></returns> public bool Compare(byte[] data, uint offset, FatType type) { BinaryFormat entry = new BinaryFormat(data); byte first = entry.GetByte(Entry.DOSName + offset); if (first == FileNameAttribute.LastEntry) return false; if ((first == FileNameAttribute.Deleted) | (first == FileNameAttribute.Dot)) return false; if (first == FileNameAttribute.Escape) return false; FatFileAttributes attribute = (FatFileAttributes)entry.GetByte(Entry.FileAttributes + offset); if ((attribute & FatFileAttributes.VolumeLabel) == FatFileAttributes.VolumeLabel) return true; return false; }
/// <summary> /// Finds the entry. /// </summary> /// <param name="compare">The compare.</param> /// <param name="startCluster">The start cluster.</param> /// <returns></returns> public FatFileLocation FindEntry(FatFileSystem.ICompare compare, uint startCluster) { uint activeSector = startCluster * sectorsPerCluster; if (startCluster == 0) activeSector = (fatType == FatType.FAT32) ? GetSectorByCluster(rootCluster32) : firstRootDirectorySector; uint increment = 0; for (;;) { BinaryFormat directory = new BinaryFormat(partition.ReadBlock(activeSector, 1)); for (uint index = 0; index < entriesPerSector; index++) { if (compare.Compare(directory.Data, index * 32, fatType)) { FatFileAttributes attribute = (FatFileAttributes)directory.GetByte((index * Entry.EntrySize) + Entry.FileAttributes); return new FatFileLocation(GetClusterEntry(directory.Data, index, fatType), activeSector, index, (attribute & FatFileAttributes.SubDirectory) != 0); } if (directory.GetByte(Entry.DOSName + (index * Entry.EntrySize)) == FileNameAttribute.LastEntry) return new FatFileLocation(); } ++increment; if ((startCluster == 0) && (fatType != FatType.FAT32)) { // FAT12/16 Root directory if (increment >= rootDirSectors) return new FatFileLocation(); activeSector = startCluster + increment; continue; } else { // subdirectory if (increment < sectorsPerCluster) { // still within cluster activeSector = startCluster + increment; continue; } // exiting cluster // goto next cluster (if any) uint cluster = GetClusterBySector(startCluster); if (cluster == 0) return new FatFileLocation(); uint nextCluster = GetClusterEntryValue(cluster); if ((IsClusterLast(nextCluster)) || (IsClusterBad(nextCluster)) || (IsClusterFree(nextCluster)) || (IsClusterReserved(nextCluster))) return new FatFileLocation(); activeSector = (uint)(dataAreaStart + (nextCluster - 1 * sectorsPerCluster)); continue; } } }
/// <summary> /// Creates the file. /// </summary> /// <param name="filename">The filename.</param> /// <param name="fileAttributes">The file attributes.</param> /// <param name="directoryCluster">The directory cluster.</param> /// <returns></returns> public FatFileLocation CreateFile(string filename, FatFileAttributes fileAttributes, uint directoryCluster) { FatFileLocation location = FindEntry(new Find.WithName(filename), directoryCluster); if (location.Valid) { // Truncate the file BinaryFormat entry = new BinaryFormat(partition.ReadBlock(location.DirectorySector, 1)); // Truncate the file length and reset the start cluster entry.SetUInt(Entry.FileSize + (location.DirectorySectorIndex * Entry.EntrySize), 0); entry.SetUInt(Entry.FirstCluster + (location.DirectorySectorIndex * Entry.EntrySize), 0); partition.WriteBlock(location.DirectorySector, 1, entry.Data); FreeClusterChain(location.FirstCluster); location.FirstCluster = 0; return location; } // Find an empty location in the directory location = FindEntry(new Find.Empty(), directoryCluster); if (!location.Valid) { // Extend Directory // TODO return location; } BinaryFormat directory = new BinaryFormat(partition.ReadBlock(location.DirectorySector, 1)); if (filename.Length > 11) filename = filename.Substring(0, 11); // Create Entry directory.SetString(Entry.DOSName + (location.DirectorySectorIndex * Entry.EntrySize), " ", 11); directory.SetString(Entry.DOSName + (location.DirectorySectorIndex * Entry.EntrySize), filename); directory.SetByte(Entry.FileAttributes + (location.DirectorySectorIndex * Entry.EntrySize), (byte)fileAttributes); directory.SetByte(Entry.Reserved + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetByte(Entry.CreationTimeFine + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.CreationTime + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.CreationDate + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.LastAccessDate + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.LastModifiedTime + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.LastModifiedDate + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.FirstCluster + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUInt(Entry.FileSize + (location.DirectorySectorIndex * Entry.EntrySize), 0); partition.WriteBlock(location.DirectorySector, 1, directory.Data); return location; }
/// <summary> /// Deletes the specified file or directory /// </summary> /// <param name="targetCluster">The target cluster.</param> /// <param name="directorySector">The directory sector.</param> /// <param name="directorySectorIndex">Index of the directory sector.</param> public void Delete(uint targetCluster, uint directorySector, uint directorySectorIndex) { BinaryFormat entry = new BinaryFormat(partition.ReadBlock(directorySector, 1)); entry.SetByte(Entry.DOSName + (directorySectorIndex * Entry.EntrySize), (byte)FileNameAttribute.Deleted); partition.WriteBlock(directorySector, 1, entry.Data); FreeClusterChain(targetCluster); }
/// <summary> /// Gets the cluster entry. /// </summary> /// <param name="data">The data.</param> /// <param name="index">The index.</param> /// <param name="type">The type.</param> /// <returns></returns> public static uint GetClusterEntry(byte[] data, uint index, FatType type) { BinaryFormat entry = new BinaryFormat(data); uint cluster = entry.GetUShort(Entry.FirstCluster + (index * Entry.EntrySize)); if (type == FatType.FAT32) cluster |= ((uint)entry.GetUShort(Entry.EAIndex + (index * Entry.EntrySize))) << 16; return cluster; }
/// <summary> /// Allocates the first cluster. /// </summary> /// <param name="directorySector">The directory sector.</param> /// <param name="directorySectorIndex">Index of the directory sector.</param> /// <returns></returns> public uint AllocateFirstCluster(uint directorySector, uint directorySectorIndex) { uint newCluster = AllocateCluster(); if (newCluster == 0) return 0; // Truncate set first cluster BinaryFormat entry = new BinaryFormat(partition.ReadBlock(directorySector, 1)); entry.SetUInt(Entry.FirstCluster + (directorySectorIndex * Entry.EntrySize), newCluster); partition.WriteBlock(directorySector, 1, entry.Data); return newCluster; }
/// <summary> /// Sets the cluster entry value. /// </summary> /// <param name="cluster">The cluster.</param> /// <param name="nextcluster">The nextcluster.</param> /// <returns></returns> protected bool SetClusterEntryValue(uint cluster, uint nextcluster) { 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)); if (fatType == FatType.FAT12) { uint clustervalue = fat.GetUShort(sectorOffset); if (cluster % 2 == 1) clustervalue = ((clustervalue & 0x000F) | (nextcluster << 4)); else clustervalue = ((clustervalue & 0xF000) | (nextcluster & 0x0FFF)); fat.SetUShort(sectorOffset, (ushort)clustervalue); } else if (fatType == FatType.FAT16) fat.SetUShort(sectorOffset, (ushort)(nextcluster & 0xFFFF)); else //if (type == FatType.FAT32) fat.SetUInt(sectorOffset, nextcluster); partition.WriteBlock(sector, nbrSectors, fat.Data); return true; }
/// <summary> /// Extracts the name of the file. /// </summary> /// <param name="directory">The directory.</param> /// <param name="index">The index.</param> /// <returns></returns> public static string ExtractFileName(byte[] directory, uint index) { // rewrite to use string BinaryFormat entry = new BinaryFormat(directory); char[] name = new char[12]; for (uint i = 0; i < 8; i++) name[i] = (char)entry.GetByte(index + i + Entry.DOSName); int len = 8; for (int i = 7; i > 0; i--) if (name[i] == ' ') len--; else break; // special case where real character is same as the delete if ((len >= 1) && (name[0] == (char)FileNameAttribute.Escape)) name[0] = (char)FileNameAttribute.Deleted; name[len] = '.'; len++; for (uint i = 0; i < 3; i++) name[len + i] = (char)entry.GetByte(index + i + Entry.DOSExtension); len = len + 3; int spaces = 0; for (int i = len - 1; i >= 0; i--) if (name[i] == ' ') spaces++; else break; if (spaces == 3) spaces = 4; len = len - spaces; // FIXME string str = string.Empty; for (uint i = 0; i < len; i++) str = str + (char)name[i]; return str; }
/// <summary> /// Writes the master boot block. /// </summary> /// <returns></returns> public bool Write() { if (!diskDevice.CanWrite) { return false; } BinaryFormat masterboot = new BinaryFormat(new byte[512]); masterboot.SetUInt(MBR.DiskSignature, diskSignature); masterboot.SetUShort(MBR.MBRSignature, MBRConstant.MBRSignature); if (code != null) for (uint index = 0; ((index < MBRConstant.CodeAreaSize) && (index < code.Length)); index++) masterboot.SetByte(index, code[index]); for (uint index = 0; index < MaxMBRPartitions; index++) if (Partitions[index].TotalBlocks != 0) { uint offset = MBR.FirstPartition + (index * 16); masterboot.SetByte(offset + PartitionRecord.Status, (byte)(Partitions[index].Bootable ? 0x80 : 0x00)); masterboot.SetByte(offset + PartitionRecord.PartitionType, Partitions[index].PartitionType); masterboot.SetUInt(offset + PartitionRecord.LBA, Partitions[index].StartLBA); masterboot.SetUInt(offset + PartitionRecord.Sectors, Partitions[index].TotalBlocks); DiskGeometry diskGeometry = new DiskGeometry(); diskGeometry.GuessGeometry(diskDevice.TotalBlocks); CHS chsStart = new CHS(); CHS chsEnd = new CHS(); chsStart.SetCHS(diskGeometry, Partitions[index].StartLBA); chsEnd.SetCHS(diskGeometry, Partitions[index].StartLBA + Partitions[index].TotalBlocks - 1); masterboot.SetByte(offset + PartitionRecord.FirstCRS, chsStart.Head); masterboot.SetByte(offset + PartitionRecord.FirstCRS + 1, (byte)((chsStart.Sector & 0x3F) | ((chsStart.Cylinder >> 8) & 0x03))); masterboot.SetByte(offset + PartitionRecord.FirstCRS + 2, (byte)(chsStart.Cylinder & 0xFF)); masterboot.SetByte(offset + PartitionRecord.LastCRS, chsEnd.Head); masterboot.SetByte(offset + PartitionRecord.LastCRS + 1, (byte)((chsEnd.Sector & 0x3F) | ((chsEnd.Cylinder >> 8) & 0x03))); masterboot.SetByte(offset + PartitionRecord.LastCRS + 2, (byte)(chsEnd.Cylinder & 0xFF)); } diskDevice.WriteBlock(0, 1, masterboot.Data); return true; }
/// <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> /// Formats the partition with specified fat settings. /// </summary> /// <param name="fatSettings">The fat settings.</param> /// <returns></returns> public bool Format(FatSettings fatSettings) { if (!partition.CanWrite) return false; this.fatType = fatSettings.FATType; bytesPerSector = 512; nbrFats = 2; totalSectors = partition.BlockCount; sectorsPerCluster = GetSectorsPerClusterByTotalSectors(fatType, totalSectors); if (sectorsPerCluster == 0) return false; if (fatType == FatType.FAT32) { reservedSectors = 32; rootEntries = 0; } else { reservedSectors = 1; rootEntries = 512; } rootDirSectors = (((rootEntries * 32) + (bytesPerSector - 1)) / bytesPerSector); uint val1 = totalSectors - (reservedSectors + rootDirSectors); uint val2 = (uint)((sectorsPerCluster * 256) + nbrFats); if (fatType == FatType.FAT32) val2 = val2 / 2; uint sectorsPerFat = (val1 + (val2 - 1)) / val2; firstRootDirectorySector = reservedSectors + sectorsPerFat; BinaryFormat bootSector = new BinaryFormat(512); bootSector.SetUInt(BootSector.JumpInstruction, 0); bootSector.SetString(BootSector.EOMName, "MOSA "); bootSector.SetUShort(BootSector.BytesPerSector, (ushort)bytesPerSector); bootSector.SetByte(BootSector.SectorsPerCluster, (byte)sectorsPerCluster); bootSector.SetUShort(BootSector.ReservedSectors, (ushort)reservedSectors); bootSector.SetByte(BootSector.FatAllocationTables, nbrFats); bootSector.SetUShort(BootSector.MaxRootDirEntries, (ushort)rootEntries); bootSector.SetUShort(BootSector.BootSectorSignature, 0xAA55); if (totalSectors > 0xFFFF) { bootSector.SetUShort(BootSector.TotalSectors16, 0); bootSector.SetUInt(BootSector.TotalSectors32, totalSectors); } else { bootSector.SetUShort(BootSector.TotalSectors16, (ushort)totalSectors); bootSector.SetUInt(BootSector.TotalSectors32, 0); } if (fatSettings.FloppyMedia) { // Default is 1.44 bootSector.SetByte(BootSector.MediaDescriptor, 0xF0); // 0xF0 = 3.5" Double Sided, 80 tracks per side, 18 sectors per track (1.44MB). } else bootSector.SetByte(BootSector.MediaDescriptor, 0xF8); // 0xF8 = Hard disk bootSector.SetUShort(BootSector.SectorsPerTrack, fatSettings.SectorsPerTrack); bootSector.SetUShort(BootSector.NumberOfHeads, fatSettings.NumberOfHeads); bootSector.SetUInt(BootSector.HiddenSectors, fatSettings.HiddenSectors); if (fatType != FatType.FAT32) { bootSector.SetUShort(BootSector.SectorsPerFAT, (ushort)sectorsPerFat); if (fatSettings.FloppyMedia) bootSector.SetByte(BootSector.PhysicalDriveNbr, 0x00); else bootSector.SetByte(BootSector.PhysicalDriveNbr, 0x80); bootSector.SetByte(BootSector.ReservedCurrentHead, 0); bootSector.SetByte(BootSector.ExtendedBootSignature, 0x29); bootSector.SetBytes(BootSector.IDSerialNumber, fatSettings.SerialID, 0, (uint)Math.Min(4, fatSettings.SerialID.Length)); if (string.IsNullOrEmpty(fatSettings.VolumeLabel)) bootSector.SetString(BootSector.VolumeLabel, "NO NAME "); else { bootSector.SetString(BootSector.VolumeLabel, " "); // 11 blank spaces bootSector.SetString(BootSector.VolumeLabel, fatSettings.VolumeLabel, (uint)Math.Min(11, fatSettings.VolumeLabel.Length)); } if (fatSettings.OSBootCode != null) { if (fatSettings.OSBootCode.Length == 512) { bootSector.SetBytes(BootSector.JumpInstruction, fatSettings.OSBootCode, BootSector.JumpInstruction, 3); bootSector.SetBytes(BootSector.OSBootCode, fatSettings.OSBootCode, BootSector.OSBootCode, 448); } else { bootSector.SetByte(BootSector.JumpInstruction, 0xEB); // 0xEB = JMP Instruction bootSector.SetByte(BootSector.JumpInstruction + 1, 0x3C); bootSector.SetByte(BootSector.JumpInstruction + 2, 0x90); bootSector.SetBytes(BootSector.OSBootCode, fatSettings.OSBootCode, 0, (uint)Math.Min(448, fatSettings.OSBootCode.Length)); } } if (fatType == FatType.FAT12) bootSector.SetString(BootSector.FATType, "FAT12 "); else bootSector.SetString(BootSector.FATType, "FAT16 "); } if (fatType == FatType.FAT32) { bootSector.SetUShort(BootSector.SectorsPerFAT, 0); bootSector.SetUInt(BootSector.FAT32_SectorPerFAT, sectorsPerFat); bootSector.SetByte(BootSector.FAT32_Flags, 0); bootSector.SetUShort(BootSector.FAT32_Version, 0); bootSector.SetUInt(BootSector.FAT32_ClusterNumberOfRoot, 2); bootSector.SetUShort(BootSector.FAT32_SectorFSInformation, 1); bootSector.SetUShort(BootSector.FAT32_SecondBootSector, 6); bootSector.SetByte(BootSector.FAT32_PhysicalDriveNbr, 0x80); bootSector.SetByte(BootSector.FAT32_Reserved2, 0); bootSector.SetByte(BootSector.FAT32_ExtendedBootSignature, 0x29); bootSector.SetBytes(BootSector.FAT32_IDSerialNumber, fatSettings.SerialID, 0, (uint)Math.Min(4, fatSettings.SerialID.Length)); bootSector.SetString(BootSector.FAT32_VolumeLabel, " "); // 11 blank spaces bootSector.SetString(BootSector.FAT32_VolumeLabel, fatSettings.VolumeLabel, (uint)(fatSettings.VolumeLabel.Length <= 11 ? fatSettings.VolumeLabel.Length : 11)); bootSector.SetString(BootSector.FAT32_FATType, "FAT32 "); if (fatSettings.OSBootCode.Length == 512) { bootSector.SetBytes(BootSector.JumpInstruction, fatSettings.OSBootCode, BootSector.JumpInstruction, 3); bootSector.SetBytes(BootSector.FAT32_OSBootCode, fatSettings.OSBootCode, BootSector.FAT32_OSBootCode, 420); } else { bootSector.SetByte(BootSector.JumpInstruction, 0xEB); // 0xEB = JMP Instruction bootSector.SetByte(BootSector.JumpInstruction + 1, 0x58); bootSector.SetByte(BootSector.JumpInstruction + 2, 0x90); bootSector.SetBytes(BootSector.FAT32_OSBootCode, fatSettings.OSBootCode, 0, (uint)Math.Min(420, fatSettings.OSBootCode.Length)); } } // Write Boot Sector partition.WriteBlock(0, 1, bootSector.Data); if (fatType == FatType.FAT32) { // Write backup Boot Sector if (fatType == FatType.FAT32) partition.WriteBlock(6, 1, bootSector.Data); // Create FSInfo Structure BinaryFormat infoSector = new BinaryFormat(512); infoSector.SetUInt(FSInfo.FSI_LeadSignature, 0x41615252); //FSInfo.FSI_Reserved1 infoSector.SetUInt(FSInfo.FSI_StructureSigature, 0x61417272); infoSector.SetUInt(FSInfo.FSI_FreeCount, 0xFFFFFFFF); infoSector.SetUInt(FSInfo.FSI_NextFree, 0xFFFFFFFF); //FSInfo.FSI_Reserved2 bootSector.SetUInt(FSInfo.FSI_TrailSignature, 0xAA550000); // Write FSInfo Structure partition.WriteBlock(1, 1, infoSector.Data); partition.WriteBlock(7, 1, infoSector.Data); // Create 2nd sector BinaryFormat secondSector = new BinaryFormat(512); secondSector.SetUShort(FSInfo.FSI_TrailSignature2, 0xAA55); partition.WriteBlock(2, 1, secondSector.Data); partition.WriteBlock(8, 1, secondSector.Data); } // Create FAT table(s) // Clear primary & secondary FATs BinaryFormat emptyFat = new BinaryFormat(512); for (uint i = 1; i < sectorsPerFat; i++) partition.WriteBlock(reservedSectors + i, 1, emptyFat.Data); if (nbrFats == 2) for (uint i = 1; i < sectorsPerFat; i++) partition.WriteBlock(reservedSectors + sectorsPerFat + i, 1, emptyFat.Data); // First FAT block is special BinaryFormat firstFat = new BinaryFormat(512); if (fatType == FatType.FAT12) { firstFat.SetByte(1, 0xFF); firstFat.SetByte(2, 0xFF); // 0xF8 } else if (fatType == FatType.FAT16) { firstFat.SetUShort(0, 0xFFFF); firstFat.SetUShort(2, 0xFFFF); // 0xFFF8 } else // if (type == FatType.FAT32) { firstFat.SetUInt(0, 0x0FFFFFFF); firstFat.SetUInt(4, 0x0FFFFFFF); // 0x0FFFFFF8 firstFat.SetUInt(8, 0x0FFFFFFF); // Also reserve the 2nd cluster for root directory } if (fatSettings.FloppyMedia) firstFat.SetByte(0, 0xF0); else firstFat.SetByte(0, 0xF8); partition.WriteBlock(reservedSectors, 1, firstFat.Data); if (nbrFats == 2) partition.WriteBlock(reservedSectors + sectorsPerFat, 1, firstFat.Data); // Create Empty Root Directory if (fatType == FatType.FAT32) { } else { for (uint i = 0; i < rootDirSectors; i++) partition.WriteBlock(firstRootDirectorySector + i, 1, emptyFat.Data); } return ReadBootSector(); }
/// <summary> /// Sets the name of the volume. /// </summary> /// <param name="volumeName">Name of the volume.</param> public void SetVolumeName(string volumeName) { if (volumeLabel.Length > 8) volumeLabel = volumeLabel.Substring(0, 8); FatFileLocation location = FindEntry(new Find.Volume(), 0); if (!location.Valid) { location = FindEntry(new Find.Empty(), 0); if (!location.Valid) return; // TODO: something went wrong } BinaryFormat directory = new BinaryFormat(partition.ReadBlock(location.DirectorySector, 1)); if (volumeName.Length > 8) volumeName = volumeName.Substring(0, 8); // Create Entry directory.SetString(Entry.DOSName + (location.DirectorySectorIndex * Entry.EntrySize), " ", 11); directory.SetString(Entry.DOSName + (location.DirectorySectorIndex * Entry.EntrySize), volumeName); directory.SetByte(Entry.FileAttributes + (location.DirectorySectorIndex * Entry.EntrySize), (byte)FatFileAttributes.VolumeLabel); directory.SetByte(Entry.Reserved + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetByte(Entry.CreationTimeFine + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.CreationTime + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.CreationDate + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.LastAccessDate + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.LastModifiedTime + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.LastModifiedDate + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUShort(Entry.FirstCluster + (location.DirectorySectorIndex * Entry.EntrySize), 0); directory.SetUInt(Entry.FileSize + (location.DirectorySectorIndex * Entry.EntrySize), 0); partition.WriteBlock(location.DirectorySector, 1, directory.Data); }
/// <summary> /// Identifies the drive. /// </summary> protected void IdentifyDrive() { byte drive = (byte)(((deviceHead & 0x10) != 0x10) ? 0 : 1); byte d = (byte)('0' + drive + 1); BinaryFormat data = new BinaryFormat(bufferData); data.Fill(0, 0, 512); // fixed drive and over 5Mb/sec data.SetUShort(0x00, 0x140); // Serial Number data.Fill(0x0A * 2, d, 20); data.SetByte(0x0A * 2, d); // Firmware version data.Fill(0x17 * 2, d, 8); data.SetChar(0x17 * 2 + 0, '1'); data.SetChar(0x17 * 2 + 1, '.'); data.SetChar(0x17 * 2 + 2, '0'); // Model Number data.Fill(0x1B * 2, d, 40); data.SetChar(0x17 * 2 + 0, 'D'); data.SetChar(0x17 * 2 + 1, 'R'); data.SetChar(0x17 * 2 + 2, 'I'); data.SetChar(0x17 * 2 + 3, 'V'); data.SetChar(0x17 * 2 + 4, 'E'); data.SetByte(0x1B * 2 + 5, d); // lba28 data.SetUInt(0x3C * 2, (uint)(driveFiles[drive].Length / 512)); commandStatus = (byte)((commandStatus | 0x08) & ~0x80); // Set DRQ (bit 3), clear BUSY (bit 7) status = DeviceStatus.IdentifyDrive; }
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); } } }
public static void PatchSyslinux_6_03(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) throw new InvalidProgramException("Unable to find syslinux.sys"); // Get the file size & number of sectors used uint fileSize = fat.GetFileSize(location.DirectorySector, location.DirectorySectorIndex); var sectors = new List<uint>(); // Create list of the sectors of the file for (uint cluster = location.FirstCluster; (cluster != 0); cluster = fat.GetNextCluster(cluster)) { uint sec = fat.GetSectorByCluster(cluster); for (uint i = 0; i < fat.SectorsPerCluster; i++) { sectors.Add(sec + i); } } // Get the ldlinux.sys file stream var ldlinux = new FatFileStream(fat, location); var ldlinuxReader = new EndianAwareBinaryReader(ldlinux, Endianness.Little); // Search for 0x3EB202FE (magic) while ((ldlinuxReader.ReadUInt32() != Syslinux.LDLINUX_MAGIC) && (ldlinux.Position < ldlinux.Length)) ; if (ldlinux.Position >= ldlinux.Length || ldlinux.Position <= 0) throw new InvalidProgramException("Unable to find patch location for syslinux"); uint patchArea = (uint)ldlinux.Position - 4; // Get Extended Patch Area offset ldlinux.Position = patchArea + Syslinux.PatchAreaOffset.EPAOffset; ushort epa = ldlinuxReader.ReadUInt16(); ldlinux.Position = epa + Syslinux.ExtendedPatchAreaOffset.Sect1Ptr0; uint sect1Ptr0 = (uint)ldlinuxReader.ReadUInt16(); ldlinux.Position = epa + Syslinux.ExtendedPatchAreaOffset.Sect1Ptr1; uint sect1Ptr1 = (uint)ldlinuxReader.ReadUInt16(); ldlinux.Position = epa + Syslinux.ExtendedPatchAreaOffset.SecPtrOffset; uint ex = (uint)ldlinuxReader.ReadUInt16(); ldlinux.Position = epa + Syslinux.ExtendedPatchAreaOffset.SecPtrCnt; uint nptrs = (uint)ldlinuxReader.ReadUInt16(); ldlinux.Position = epa + Syslinux.ExtendedPatchAreaOffset.AdvPtrOffset; uint advptrs = (uint)ldlinuxReader.ReadUInt16(); if (sectors.Count > nptrs) throw new InvalidProgramException("Insufficient space for patching syslinux"); var ldlinuxWriter = new EndianAwareBinaryWriter(ldlinux, Endianness.Little); // Set up the totals ldlinux.Position = patchArea + Syslinux.PatchAreaOffset.DataSectors; ldlinuxWriter.Write((ushort)sectors.Count); ldlinux.Position = patchArea + Syslinux.PatchAreaOffset.DataSectors; ldlinuxWriter.Write((ushort)2); ldlinux.Position = patchArea + Syslinux.PatchAreaOffset.DataSectors; ldlinuxWriter.Write((uint)fileSize >> 2); // Generate Extents var extents = GenerateExtents(sectors); ldlinux.Position = ex; // Write out extents foreach (var extent in extents) { ldlinuxWriter.Write((ulong)extent.Start); ldlinuxWriter.Write((ushort)extent.Length); } // Write out ADV ldlinux.Position = advptrs; ldlinuxWriter.Write((ulong)sectors[sectors.Count - 2]); ldlinuxWriter.Write((ulong)sectors[sectors.Count - 1]); // Clear out checksum ldlinux.Position = patchArea + Syslinux.PatchAreaOffset.Checksum; ldlinuxWriter.Write((uint)0); // Write back the updated cluster ldlinuxWriter.Flush(); // Re-Calculate checksum ldlinux.Position = 0; uint csum = Syslinux.LDLINUX_MAGIC; for (uint index = 0; index < (ldlinux.Length >> 2); index++) { csum = csum + ldlinuxReader.ReadUInt32(); } // Set the checksum ldlinux.Position = patchArea + Syslinux.PatchAreaOffset.Checksum; ldlinuxWriter.Write(csum); // Write patched cluster back to disk ldlinuxWriter.Flush(); // Read boot sector var fatBootSector = new BinaryFormat(partitionDevice.ReadBlock(0, 1)); // Set the first sector location of the file fatBootSector.SetUInt(sect1Ptr0, fat.GetSectorByCluster(location.FirstCluster)); fatBootSector.SetUInt(sect1Ptr1, 0); // since only 32-bit offsets are support, the high portion of 64-bit value is zero // Write back patched boot sector partitionDevice.WriteBlock(0, 1, fatBootSector.Data); }
/// <summary> /// Reads the LBA48. /// </summary> /// <param name="operation">The operation.</param> /// <param name="drive">The drive.</param> /// <param name="lba">The lba.</param> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <returns></returns> protected bool ReadLBA48(SectorOperation operation, uint drive, uint lba, byte[] data, uint offset) { if (drive > MaximunDriveCount) return false; FeaturePort.Write8(0); FeaturePort.Write8(0); SectorCountPort.Write8(0); SectorCountPort.Write8(1); LBALowPort.Write8((byte)((lba >> 24) & 0xFF)); LBALowPort.Write8((byte)(lba & 0xFF)); LBAMidPort.Write8((byte)((lba >> 32) & 0xFF)); LBAMidPort.Write8((byte)((lba >> 8) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 40) & 0xFF)); LBAHighPort.Write8((byte)((lba >> 16) & 0xFF)); DeviceHeadPort.Write8((byte)(0x40 | (drive << 4))); if (operation == SectorOperation.Write) CommandPort.Write8(0x34); else CommandPort.Write8(0x24); if (!WaitForRegisterReady()) return false; var sector = new BinaryFormat(data); //TODO: Don't use PIO if (operation == SectorOperation.Read) { for (uint index = 0; index < 256; index++) sector.SetUShort(offset + (index * 2), DataPort.Read16()); } else { for (uint index = 0; index < 256; index++) DataPort.Write16(sector.GetUShort(offset + (index * 2))); } return true; }
/// <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> /// 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> /// Updates the length. /// </summary> /// <param name="size">The size.</param> /// <param name="firstCluster">The first cluster.</param> /// <param name="directorySector">The directory sector.</param> /// <param name="directorySectorIndex">Index of the directory sector.</param> public void UpdateLength(uint size, uint firstCluster, uint directorySector, uint directorySectorIndex) { // Truncate the file BinaryFormat entry = new BinaryFormat(partition.ReadBlock(directorySector, 1)); // Truncate the file length and set entry.SetUInt(Entry.FileSize + (directorySectorIndex * Entry.EntrySize), size); if (size == 0) entry.SetUInt(Entry.FirstCluster + (directorySectorIndex * Entry.EntrySize), 0); partition.WriteBlock(directorySector, 1, entry.Data); if (size == 0) FreeClusterChain(firstCluster); }
/// <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; }
/// <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; }