/// <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> /// 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; }