diff --git a/source/Cosmos.System2/FileSystem/FAT/BiosParameterBlock.cs b/source/Cosmos.System2/FileSystem/FAT/BiosParameterBlock.cs new file mode 100644 index 000000000..35d3c52dd --- /dev/null +++ b/source/Cosmos.System2/FileSystem/FAT/BiosParameterBlock.cs @@ -0,0 +1,82 @@ +using System.Text; + +namespace Cosmos.System.FileSystem.FAT +{ + internal sealed class BiosParameterBlock : DataStructure + { + public static readonly ByteField JmpBoot0 = new ByteField(0); + public static readonly ByteField JmpBoot1 = new ByteField(1); + public static readonly ByteField JmpBoot2 = new ByteField(2); + + public static readonly StringField OemName = new StringField(3, 8, Encoding.ASCII); + + public static readonly UInt16Field BytesPerSector = new UInt16Field(11); + public static readonly ByteField SectorsPerCluster = new ByteField(13); + + public static readonly UInt16Field ReservedSectorCount = new UInt16Field(14); + + public static readonly ByteField FatCount = new ByteField(16); + + public static readonly UInt16Field RootEntryCount = new UInt16Field(17); + + public static readonly UInt16Field TotalSectorCount16 = new UInt16Field(19); + + public static readonly EnumField MediaKind = new EnumField(new ByteField(21)); + + public static readonly UInt16Field FatSectorCount16 = new UInt16Field(22); + + public static readonly UInt16Field SectorsPerTrack = new UInt16Field(24); + public static readonly UInt16Field HeadCount = new UInt16Field(26); + public static readonly UInt32Field HiddenSectorCount = new UInt32Field(28); + + public static readonly UInt32Field TotalSectorCount32 = new UInt32Field(32); + + public static readonly UInt16Field Signature = new UInt16Field(510); + + public static class Fat12 + { + public static readonly ByteField DriveNumber = new ByteField(36); + + public static readonly ByteField Reserved1 = new ByteField(37); + + public static readonly ByteField BootSignature = new ByteField(38); + + public static readonly UInt32Field VolumeId = new UInt32Field(39); + public static readonly StringField VolumeLabel = new StringField(43, 11, Encoding.ASCII); + + public static readonly StringField FileSystemType = new StringField(54, 8, Encoding.ASCII); + } + + public static class Fat32 + { + public static readonly UInt32Field FatSectorCount32 = new UInt32Field(36); + + public static readonly EnumField ExtendedFlags = + new EnumField(new UInt16Field(40)); + + public static readonly UInt16Field FileSystemVersion = new UInt16Field(42); + + public static readonly UInt32Field RootCluster = new UInt32Field(44); + + public static readonly UInt16Field FileSystemInfo = new UInt16Field(48); + + public static readonly UInt16Field BackupBootSector = new UInt16Field(50); + + public static readonly ByteField DriveNumber = new ByteField(64); + + public static readonly ByteField Reserved1 = new ByteField(65); + + public static readonly ByteField BootSignature = new ByteField(66); + + public static readonly UInt32Field VolumeId = new UInt32Field(67); + public static readonly StringField VolumeLabel = new StringField(71, 11, Encoding.ASCII); + + public static readonly StringField FileSystemType = new StringField(82, 8, Encoding.ASCII); + } + + public BiosParameterBlock(byte[] data) + : base(data) + { + } + } +} diff --git a/source/Cosmos.System2/FileSystem/FAT/DataStructures.cs b/source/Cosmos.System2/FileSystem/FAT/DataStructures.cs new file mode 100644 index 000000000..432f95b49 --- /dev/null +++ b/source/Cosmos.System2/FileSystem/FAT/DataStructures.cs @@ -0,0 +1,147 @@ +using System; +using System.Text; + +namespace Cosmos.System.FileSystem.FAT +{ + internal abstract class DataStructure + { + protected DataStructure(byte[] data) + { + Data = data ?? throw new ArgumentNullException(nameof(data)); + } + + protected byte[] Data { get; } + + public T GetValue(Field field) => field.GetValue(Data); + + public void SetValue(Field field, T value) => field.SetValue(Data, value); + } + + internal abstract class Field + { + public Field(int position, int length) + { + Position = position; + Length = length; + } + + /// + /// Position, in bytes, of the field. + /// + public int Position { get; } + /// + /// Length, in bytes, of the field. + /// + public int Length { get; } + + /// + /// Gets the value for this field from the data structure. + /// + /// A byte array which contains a data structure for which this field was defined. + /// The field value. + public abstract T GetValue(byte[] data); + + /// + /// Sets the value for this field on the data structure. + /// + /// A byte array which contains a data structure for which this field was defined. + /// The value to set this field to. + public abstract void SetValue(byte[] data, T value); + } + + internal class ByteField : Field + { + public ByteField(int position) + : base(position, 1) + { + } + + public override byte GetValue(byte[] data) => data[Position]; + + public override void SetValue(byte[] data, byte value) => data[Position] = value; + } + + internal class UInt16Field : Field + { + public UInt16Field(int position) + : base(position, 2) + { + } + + public override ushort GetValue(byte[] data) => BitConverter.ToUInt16(data, Position); + + public override void SetValue(byte[] data, ushort value) + { + data[Position] = (byte)value; + data[Position + 1] = (byte)(value >> 8); + } + } + + internal class Int32Field : Field + { + public Int32Field(int position) + : base(position, 4) + { + } + + public override int GetValue(byte[] data) => BitConverter.ToInt32(data, Position); + + public override void SetValue(byte[] data, int value) + { + data[Position] = (byte)value; + data[Position + 1] = (byte)(value >> 8); + data[Position + 2] = (byte)(value >> 16); + data[Position + 3] = (byte)(value >> 24); + } + } + + internal class UInt32Field : Field + { + public UInt32Field(int position) + : base(position, 4) + { + } + + public override uint GetValue(byte[] data) => BitConverter.ToUInt32(data, Position); + + public override void SetValue(byte[] data, uint value) + { + data[Position] = (byte)value; + data[Position + 1] = (byte)(value >> 8); + data[Position + 2] = (byte)(value >> 16); + data[Position + 3] = (byte)(value >> 24); + } + } + + internal class StringField : Field + { + public StringField(int position, int length, Encoding encoding) + : base(position, length) + { + Encoding = encoding; + } + + public Encoding Encoding { get; } + + public override string GetValue(byte[] data) => Encoding.GetString(data, Position, Length); + + public override void SetValue(byte[] data, string value) => Encoding.GetBytes(value, 0, Length, data, Position); + } + + internal class EnumField : Field + { + private static readonly EnumField test = new EnumField(new Int32Field(12)); + + private readonly Field _innerField; + + public EnumField(Field innerField) + : base(innerField.Position, innerField.Length) + { + _innerField = innerField; + } + + public override TEnum GetValue(byte[] data) => (TEnum)(object)_innerField.GetValue(data); + + public override void SetValue(byte[] data, TEnum value) => _innerField.SetValue(data, (TEnumUnderlyingType)(object)value); + } +} diff --git a/source/Cosmos.System2/FileSystem/FAT/Fat32ExtendedFlags.cs b/source/Cosmos.System2/FileSystem/FAT/Fat32ExtendedFlags.cs new file mode 100644 index 000000000..f0b4f4a1b --- /dev/null +++ b/source/Cosmos.System2/FileSystem/FAT/Fat32ExtendedFlags.cs @@ -0,0 +1,11 @@ +using System; + +namespace Cosmos.System.FileSystem.FAT +{ + [Flags] + internal enum Fat32ExtendedFlags + { + ActiveFatMask = 0x000F, + Mirrored = 0x0080 + } +} diff --git a/source/Cosmos.System2/FileSystem/FAT/FatFileSystem.cs b/source/Cosmos.System2/FileSystem/FAT/FatFileSystem.cs index 817f328d0..9542f8ec5 100644 --- a/source/Cosmos.System2/FileSystem/FAT/FatFileSystem.cs +++ b/source/Cosmos.System2/FileSystem/FAT/FatFileSystem.cs @@ -7,6 +7,8 @@ using Cosmos.Common.Extensions; using Cosmos.HAL.BlockDevice; using Cosmos.System.FileSystem.FAT.Listing; using Cosmos.System.FileSystem.Listing; +using Fields = Cosmos.System.FileSystem.FAT.BiosParameterBlock; +using static Cosmos.System.FileSystem.FAT.BiosParameterBlock; namespace Cosmos.System.FileSystem.FAT { @@ -25,12 +27,7 @@ namespace Cosmos.System.FileSystem.FAT /// The first sector of the FAT table. public Fat(FatFileSystem aFileSystem, ulong aFatSector) { - if (aFileSystem == null) - { - throw new ArgumentNullException(nameof(aFileSystem)); - } - - mFileSystem = aFileSystem; + mFileSystem = aFileSystem ?? throw new ArgumentNullException(nameof(aFileSystem)); mFatSector = aFatSector; } @@ -41,15 +38,15 @@ namespace Cosmos.System.FileSystem.FAT /// Can not get the FAT entry size for an unknown FAT type. private uint GetFatEntrySizeInBytes() { - switch (mFileSystem.mFatType) + switch (mFileSystem.FatKind) { - case FatTypeEnum.Fat32: + case FatKind.Fat32: return 4; - case FatTypeEnum.Fat16: + case FatKind.Fat16: return 2; - case FatTypeEnum.Fat12: + case FatKind.Fat12: // TODO: break; } @@ -72,9 +69,8 @@ namespace Cosmos.System.FileSystem.FAT Global.mFileSystemDebugger.SendInternal("aDataSize ="); Global.mFileSystemDebugger.SendInternal(aDataSize); - var xReturn = new uint[0]; + var xReturn = Array.Empty(); uint xCurrentEntry = aFirstEntry; - uint xValue; long xEntriesRequired = aDataSize / mFileSystem.BytesPerCluster; if (aDataSize % mFileSystem.BytesPerCluster != 0) @@ -82,7 +78,7 @@ namespace Cosmos.System.FileSystem.FAT xEntriesRequired++; } - GetFatEntry(xCurrentEntry, out xValue); + GetFatEntry(xCurrentEntry, out var xValue); Array.Resize(ref xReturn, xReturn.Length + 1); xReturn[xReturn.Length - 1] = xCurrentEntry; @@ -145,8 +141,7 @@ namespace Cosmos.System.FileSystem.FAT uint xTotalEntries = mFileSystem.FatSectorCount * mFileSystem.BytesPerSector / GetFatEntrySizeInBytes(); for (uint i = mFileSystem.RootCluster; i < xTotalEntries; i++) { - uint xEntryValue; - GetFatEntry(i, out xEntryValue); + GetFatEntry(i, out var xEntryValue); if (!FatEntryIsEof(xEntryValue)) { Global.mFileSystemDebugger.SendInternal("i ="); @@ -172,17 +167,15 @@ namespace Cosmos.System.FileSystem.FAT uint xEntrySize = GetFatEntrySizeInBytes(); ulong xEntryOffset = aEntryNumber * xEntrySize; - - - switch (mFileSystem.mFatType) + switch (mFileSystem.FatKind) { - case FatTypeEnum.Fat12: + case FatKind.Fat12: aData.SetUInt16(xEntryOffset, (ushort)aValue); break; - case FatTypeEnum.Fat16: + case FatKind.Fat16: aData.SetUInt16(xEntryOffset, (ushort)aValue); break; - case FatTypeEnum.Fat32: + case FatKind.Fat32: aData.SetUInt32(xEntryOffset, (uint)aValue); break; default: @@ -195,9 +188,9 @@ namespace Cosmos.System.FileSystem.FAT uint xEntrySize = GetFatEntrySizeInBytes(); ulong xEntryOffset = aEntryNumber * xEntrySize; - switch (mFileSystem.mFatType) + switch (mFileSystem.FatKind) { - case FatTypeEnum.Fat12: + case FatKind.Fat12: // We now access the FAT entry as a WORD just as we do for FAT16, but if the cluster number is // EVEN, we only want the low 12-bits of the 16-bits we fetch. If the cluster number is ODD // we want the high 12-bits of the 16-bits we fetch. @@ -211,10 +204,10 @@ namespace Cosmos.System.FileSystem.FAT aValue = xResult >> 4; // Odd } break; - case FatTypeEnum.Fat16: + case FatKind.Fat16: aValue = BitConverter.ToUInt16(aData, (int)xEntryOffset); break; - case FatTypeEnum.Fat32: + case FatKind.Fat32: aValue = BitConverter.ToUInt32(aData, (int)xEntryOffset) & 0x0FFFFFFF; break; default: @@ -232,8 +225,7 @@ namespace Cosmos.System.FileSystem.FAT Global.mFileSystemDebugger.SendInternal($"RootCluster is {mFileSystem.RootCluster}"); Global.mFileSystemDebugger.SendInternal("Clearing all Fat Table"); - byte[] xFatTableFistSector; - ReadFatSector(0, out xFatTableFistSector); + ReadFatSector(0, out var xFatTableFistSector); /* Change 3rd entry (RootDirectory) to be EOC */ SetFatEntry(xFatTableFistSector, 2, FatEntryEofValue()); @@ -312,9 +304,9 @@ namespace Cosmos.System.FileSystem.FAT ReadFatSector(xSector, out xData); - switch (mFileSystem.mFatType) + switch (mFileSystem.FatKind) { - case FatTypeEnum.Fat12: + case FatKind.Fat12: // We now access the FAT entry as a WORD just as we do for FAT16, but if the cluster number is // EVEN, we only want the low 12-bits of the 16-bits we fetch. If the cluster number is ODD // we want the high 12-bits of the 16-bits we fetch. @@ -329,11 +321,11 @@ namespace Cosmos.System.FileSystem.FAT } break; - case FatTypeEnum.Fat16: + case FatKind.Fat16: aValue = BitConverter.ToUInt16(xData, (int)xEntryOffset); break; - case FatTypeEnum.Fat32: + case FatKind.Fat32: aValue = BitConverter.ToUInt32(xData, (int)xEntryOffset) & 0x0FFFFFFF; break; @@ -364,20 +356,17 @@ namespace Cosmos.System.FileSystem.FAT byte[] xData; ReadFatSector(xSector, out xData); - switch (mFileSystem.mFatType) + switch (mFileSystem.FatKind) { - case FatTypeEnum.Fat12: + case FatKind.Fat12: xData.SetUInt16(xEntryOffset, (ushort)aValue); break; - - case FatTypeEnum.Fat16: + case FatKind.Fat16: xData.SetUInt16(xEntryOffset, (ushort)aValue); break; - - case FatTypeEnum.Fat32: + case FatKind.Fat32: xData.SetUInt32(xEntryOffset, (uint)aValue); break; - default: throw new NotSupportedException("Unknown FAT type."); } @@ -393,188 +382,170 @@ namespace Cosmos.System.FileSystem.FAT /// Unknown file system type. private bool FatEntryIsEof(ulong aValue) { - switch (mFileSystem.mFatType) + switch (mFileSystem.FatKind) { - case FatTypeEnum.Fat12: + case FatKind.Fat12: return aValue >= 0xFF8; - - case FatTypeEnum.Fat16: + case FatKind.Fat16: return aValue >= 0xFFF8; - - case FatTypeEnum.Fat32: + case FatKind.Fat32: return aValue >= 0xFFFFFF8; - default: throw new Exception("Unknown file system type."); } } /// - /// The the EOF value for a specific FAT type. + /// The EOF value for a specific FAT type. /// /// The EOF value. /// Unknown file system type. private ulong FatEntryEofValue() { - switch (mFileSystem.mFatType) + switch (mFileSystem.FatKind) { - case FatTypeEnum.Fat12: + case FatKind.Fat12: return 0x0FFF; - - case FatTypeEnum.Fat16: + case FatKind.Fat16: return 0xFFFF; - - case FatTypeEnum.Fat32: + case FatKind.Fat32: return 0x0FFFFFFF; - default: throw new Exception("Unknown file system type."); } } } - public readonly uint BytesPerCluster; - - public readonly uint BytesPerSector; - - public readonly uint ClusterCount; - - public readonly uint DataSector; // First Data Sector - - public readonly uint DataSectorCount; - - public readonly uint FatSectorCount; - - private readonly FatTypeEnum mFatType; - - public readonly uint NumberOfFATs; - - public readonly uint ReservedSectorCount; - - public readonly uint RootCluster; // FAT32 - - public readonly uint RootEntryCount; - - public readonly uint RootSector; // FAT12/16 - - public readonly uint RootSectorCount; // FAT12/16, FAT32 remains 0 - - public readonly uint SectorsPerCluster; - - public readonly uint TotalSectorCount; - private readonly Fat[] mFats; - public override string Type - { - get - { - switch (mFatType) - { - case FatTypeEnum.Fat12: - return "FAT12"; - - case FatTypeEnum.Fat16: - return "FAT16"; - - case FatTypeEnum.Fat32: - return "FAT32"; - - default: - throw new Exception("Unknown FAT file system type."); - } - } - } - /// /// Initializes a new instance of the class. /// /// The partition. /// The root path. /// FAT signature not found. - public FatFileSystem(Partition aDevice, string aRootPath, long aSize) + public FatFileSystem(BiosParameterBlock bpb, Partition aDevice, string aRootPath, long aSize) : base(aDevice, aRootPath, aSize) { - if (aDevice == null) - { - throw new ArgumentNullException(nameof(aDevice)); - } + BiosParameterBlock = bpb; - if (String.IsNullOrEmpty(aRootPath)) - { - throw new ArgumentException("Argument is null or empty", nameof(aRootPath)); - } + BytesPerSector = BiosParameterBlock.GetValue(Fields.BytesPerSector); + SectorsPerCluster = BiosParameterBlock.GetValue(Fields.SectorsPerCluster); - var xBPB = Device.NewBlockArray(1); + BytesPerCluster = (uint)(BytesPerSector * SectorsPerCluster); - Device.ReadBlock(0UL, 1U, xBPB); + ReservedSectorCount = BiosParameterBlock.GetValue(Fields.ReservedSectorCount); - ushort xSig = BitConverter.ToUInt16(xBPB, 510); - if (xSig != 0xAA55) - { - throw new Exception("FAT signature not found."); - } + FatCount = BiosParameterBlock.GetValue(Fields.FatCount); - BytesPerSector = BitConverter.ToUInt16(xBPB, 11); - SectorsPerCluster = xBPB[13]; - BytesPerCluster = BytesPerSector * SectorsPerCluster; - ReservedSectorCount = BitConverter.ToUInt16(xBPB, 14); - NumberOfFATs = xBPB[16]; - RootEntryCount = BitConverter.ToUInt16(xBPB, 17); + var rootEntryCount = BiosParameterBlock.GetValue(Fields.RootEntryCount); - TotalSectorCount = BitConverter.ToUInt16(xBPB, 19); - if (TotalSectorCount == 0) - { - TotalSectorCount = BitConverter.ToUInt32(xBPB, 32); - } + // 1. + RootDirectorySectorCount = (uint)(((rootEntryCount * 32) + (BytesPerSector - 1)) / BytesPerSector); + + // 2. + FatSectorCount = BiosParameterBlock.GetValue(Fields.FatSectorCount16); - // FATSz - FatSectorCount = BitConverter.ToUInt16(xBPB, 22); if (FatSectorCount == 0) { - FatSectorCount = BitConverter.ToUInt32(xBPB, 36); + FatSectorCount = BiosParameterBlock.GetValue(Fat32.FatSectorCount32); } - DataSectorCount = TotalSectorCount - - (ReservedSectorCount + NumberOfFATs * FatSectorCount + ReservedSectorCount); + TotalSectorCount = BiosParameterBlock.GetValue(Fields.TotalSectorCount16); - // Computation rounds down. + if (TotalSectorCount == 0) + { + TotalSectorCount = BiosParameterBlock.GetValue(Fields.TotalSectorCount32); + } + + FirstDataSector = ReservedSectorCount + (FatCount * FatSectorCount) + RootDirectorySectorCount; + DataSectorCount = TotalSectorCount - FirstDataSector; + + // 3. ClusterCount = DataSectorCount / SectorsPerCluster; - // Determine the FAT type. Do not use another method - this IS the official and - // proper way to determine FAT type. - // Comparisons are purposefully < and not <= - // FAT16 starts at 4085, FAT32 starts at 65525 + if (ClusterCount < 4085) { - mFatType = FatTypeEnum.Fat12; + FatKind = FatKind.Fat12; } else if (ClusterCount < 65525) { - mFatType = FatTypeEnum.Fat16; + FatKind = FatKind.Fat16; } else { - mFatType = FatTypeEnum.Fat32; + FatKind = FatKind.Fat32; } - if (mFatType == FatTypeEnum.Fat32) + if (FatKind == FatKind.Fat32) { - RootCluster = BitConverter.ToUInt32(xBPB, 44); + RootCluster = BiosParameterBlock.GetValue(Fat32.RootCluster); } else { - RootSector = ReservedSectorCount + NumberOfFATs * FatSectorCount; - RootSectorCount = (RootEntryCount * 32 + (BytesPerSector - 1)) / BytesPerSector; + RootSector = ReservedSectorCount + FatCount * FatSectorCount; } - DataSector = ReservedSectorCount + NumberOfFATs * FatSectorCount + RootSectorCount; - mFats = new Fat[NumberOfFATs]; - for (ulong i = 0; i < NumberOfFATs; i++) + mFats = new Fat[FatCount]; + for (ulong i = 0; i < FatCount; i++) { mFats[i] = new Fat(this, (ReservedSectorCount + i * FatSectorCount)); } } + public FatKind FatKind { get; } + + protected BiosParameterBlock BiosParameterBlock { get; } + + protected ushort BytesPerSector { get; } + + protected byte SectorsPerCluster { get; } + + public uint BytesPerCluster { get; } + + protected ushort ReservedSectorCount { get; } + + protected byte FatCount { get; } + + protected uint RootDirectorySectorCount { get; } + + protected uint FatSectorCount { get; } + + protected uint TotalSectorCount { get; } + + protected uint FirstDataSector { get; } + + protected uint DataSectorCount { get; } + + protected uint ClusterCount { get; } + + // FAT12/16 + public uint RootSector { get; } + + // FAT32 + public uint RootCluster { get; } + + public override string Type + { + get + { + switch (FatKind) + { + case FatKind.Fat12: + return "FAT12"; + + case FatKind.Fat16: + return "FAT16"; + + case FatKind.Fat32: + return "FAT32"; + + default: + throw new Exception("Unknown FAT file system type."); + } + } + } + internal Fat GetFat(int aTableNumber) { if (mFats.Length > aTableNumber) @@ -582,7 +553,7 @@ namespace Cosmos.System.FileSystem.FAT return mFats[aTableNumber]; } - throw new Exception("The fat table number doesn't exist."); + throw new Exception("The FAT table number doesn't exist."); } internal byte[] NewBlockArray() @@ -599,16 +570,16 @@ namespace Cosmos.System.FileSystem.FAT aSize = BytesPerCluster; } - if (mFatType == FatTypeEnum.Fat32) + if (FatKind == FatKind.Fat32) { aData = NewBlockArray(); - long xSector = DataSector + (aCluster - RootCluster) * SectorsPerCluster; + long xSector = FirstDataSector + (aCluster - RootCluster) * SectorsPerCluster; Device.ReadBlock((ulong)xSector, SectorsPerCluster, aData); } else { aData = Device.NewBlockArray(1); - Device.ReadBlock((ulong)aCluster, RootSectorCount, aData); + Device.ReadBlock((ulong)aCluster, RootDirectorySectorCount, aData); } } @@ -626,19 +597,19 @@ namespace Cosmos.System.FileSystem.FAT aSize = BytesPerCluster; } - byte[] xData; - - Read(aCluster, out xData); + Read(aCluster, out var xData); Array.Copy(aData, 0, xData, aOffset, aData.Length); - if (mFatType == FatTypeEnum.Fat32) + + + if (FatKind == FatKind.Fat32) { - long xSector = DataSector + (aCluster - RootCluster) * SectorsPerCluster; + long xSector = FirstDataSector + (aCluster - RootCluster) * SectorsPerCluster; Device.WriteBlock((ulong)xSector, SectorsPerCluster, xData); } else { - Device.WriteBlock((ulong)aCluster, RootSectorCount, xData); + Device.WriteBlock((ulong)aCluster, RootSector, xData); } } @@ -648,16 +619,15 @@ namespace Cosmos.System.FileSystem.FAT global::System.Console.WriteLine("Bytes per Cluster = " + BytesPerCluster); global::System.Console.WriteLine("Bytes per Sector = " + BytesPerSector); global::System.Console.WriteLine("Cluster Count = " + ClusterCount); - global::System.Console.WriteLine("Data Sector = " + DataSector); + global::System.Console.WriteLine("First Data Sector = " + FirstDataSector); global::System.Console.WriteLine("Data Sector Count = " + DataSectorCount); global::System.Console.WriteLine("FAT Sector Count = " + FatSectorCount); - global::System.Console.WriteLine("FAT Type = " + (uint)mFatType); - global::System.Console.WriteLine("Number of FATS = " + NumberOfFATs); + global::System.Console.WriteLine("FAT Kind = " + (uint)FatKind); + global::System.Console.WriteLine("Number of FATs = " + FatCount); global::System.Console.WriteLine("Reserved Sector Count = " + ReservedSectorCount); global::System.Console.WriteLine("Root Cluster = " + RootCluster); - global::System.Console.WriteLine("Root Entry Count = " + RootEntryCount); - global::System.Console.WriteLine("Root Sector = " + RootSector); - global::System.Console.WriteLine("Root Sector Count = " + RootSectorCount); + global::System.Console.WriteLine("Root Entry Count = " + BiosParameterBlock.GetValue(Fields.RootEntryCount)); + global::System.Console.WriteLine("Root Sector Count = " + RootDirectorySectorCount); global::System.Console.WriteLine("Sectors per Cluster = " + SectorsPerCluster); global::System.Console.WriteLine("Total Sector Count = " + TotalSectorCount); @@ -667,26 +637,24 @@ namespace Cosmos.System.FileSystem.FAT Global.mFileSystemDebugger.SendInternal(BytesPerSector); Global.mFileSystemDebugger.SendInternal("Cluster Count ="); Global.mFileSystemDebugger.SendInternal(ClusterCount); - Global.mFileSystemDebugger.SendInternal("Data Sector ="); - Global.mFileSystemDebugger.SendInternal(DataSector); + Global.mFileSystemDebugger.SendInternal("First Data Sector ="); + Global.mFileSystemDebugger.SendInternal(FirstDataSector); Global.mFileSystemDebugger.SendInternal("Data Sector Count ="); Global.mFileSystemDebugger.SendInternal(DataSectorCount); Global.mFileSystemDebugger.SendInternal("FAT Sector Count ="); Global.mFileSystemDebugger.SendInternal(FatSectorCount); Global.mFileSystemDebugger.SendInternal("FAT Type ="); - Global.mFileSystemDebugger.SendInternal((uint)mFatType); - Global.mFileSystemDebugger.SendInternal("Number of FATS ="); - Global.mFileSystemDebugger.SendInternal(NumberOfFATs); + Global.mFileSystemDebugger.SendInternal((uint)FatKind); + Global.mFileSystemDebugger.SendInternal("Number of FATs ="); + Global.mFileSystemDebugger.SendInternal(FatCount); Global.mFileSystemDebugger.SendInternal("Reserved Sector Count ="); Global.mFileSystemDebugger.SendInternal(ReservedSectorCount); Global.mFileSystemDebugger.SendInternal("Root Cluster ="); Global.mFileSystemDebugger.SendInternal(RootCluster); Global.mFileSystemDebugger.SendInternal("Root Entry Count ="); - Global.mFileSystemDebugger.SendInternal(RootEntryCount); - Global.mFileSystemDebugger.SendInternal("Root Sector ="); - Global.mFileSystemDebugger.SendInternal(RootSector); + Global.mFileSystemDebugger.SendInternal(BiosParameterBlock.GetValue(Fields.RootEntryCount)); Global.mFileSystemDebugger.SendInternal("Root Sector Count ="); - Global.mFileSystemDebugger.SendInternal(RootSectorCount); + Global.mFileSystemDebugger.SendInternal(RootDirectorySectorCount); Global.mFileSystemDebugger.SendInternal("Sectors per Cluster ="); Global.mFileSystemDebugger.SendInternal(SectorsPerCluster); Global.mFileSystemDebugger.SendInternal("Total Sector Count ="); @@ -869,17 +837,6 @@ namespace Cosmos.System.FileSystem.FAT } } - private enum FatTypeEnum - { - Unknown, - - Fat12, - - Fat16, - - Fat32 - } - public override void Format(string aDriveFormat, bool aQuick) { var xRootDirectory = (FatDirectoryEntry)GetRootDirectory(); diff --git a/source/Cosmos.System2/FileSystem/FAT/FatFileSystemFactory.cs b/source/Cosmos.System2/FileSystem/FAT/FatFileSystemFactory.cs new file mode 100644 index 000000000..9663dd609 --- /dev/null +++ b/source/Cosmos.System2/FileSystem/FAT/FatFileSystemFactory.cs @@ -0,0 +1,54 @@ +using System; + +using Cosmos.HAL.BlockDevice; + +namespace Cosmos.System.FileSystem.FAT +{ + public class FatFileSystemFactory : FileSystemFactory + { + public override string Name => "FAT"; + + public override bool IsType(Partition aDevice) + { + if (aDevice == null) + { + throw new ArgumentNullException(nameof(aDevice)); + } + + var bootSector = ReadBootSector(aDevice); + var bpb = new BiosParameterBlock(bootSector); + + return IsFatPartition(bpb); + } + + /// + /// Initializes a new instance of the class. + /// + /// The partition. + /// The root path. + /// FAT signature not found. + public override FileSystem Create(Partition aDevice, string aRootPath, long aSize) + { + var bootSector = ReadBootSector(aDevice); + var bpb = new BiosParameterBlock(bootSector); + + if (!IsFatPartition(bpb)) + { + throw new InvalidOperationException("Partition file system is not FAT!"); + } + + return new FatFileSystem(bpb, aDevice, aRootPath, aSize); + } + + private byte[] ReadBootSector(Partition partition) + { + var bootSector = partition.NewBlockArray(1); + partition.ReadBlock(0, 1, bootSector); + + return bootSector; + } + + private bool IsFatPartition(BiosParameterBlock bpb) => + bpb.GetValue(BiosParameterBlock.Signature) == 0xAA55; + } +} diff --git a/source/Cosmos.System2/FileSystem/FAT/FatKind.cs b/source/Cosmos.System2/FileSystem/FAT/FatKind.cs new file mode 100644 index 000000000..a35b6d20c --- /dev/null +++ b/source/Cosmos.System2/FileSystem/FAT/FatKind.cs @@ -0,0 +1,10 @@ +namespace Cosmos.System.FileSystem.FAT +{ + internal enum FatKind + { + Unkown, + Fat12, + Fat16, + Fat32 + } +} diff --git a/source/Cosmos.System2/FileSystem/FAT/FatMediaKind.cs b/source/Cosmos.System2/FileSystem/FAT/FatMediaKind.cs new file mode 100644 index 000000000..1e707c442 --- /dev/null +++ b/source/Cosmos.System2/FileSystem/FAT/FatMediaKind.cs @@ -0,0 +1,15 @@ +namespace Cosmos.System.FileSystem.FAT +{ + public enum FatMediaKind + { + Removable = 0xF0, + Fixed = 0xF8, + Floppy1 = 0xF9, + Floppy2 = 0xFA, + Floppy3 = 0xFB, + Floppy4 = 0xFC, + Floppy5 = 0xFD, + Floppy6 = 0xFE, + Floppy7 = 0xFF + } +} diff --git a/source/Cosmos.System2/FileSystem/FAT/FatStream.cs b/source/Cosmos.System2/FileSystem/FAT/FatStream.cs index 1266ca689..2b18b70d7 100644 --- a/source/Cosmos.System2/FileSystem/FAT/FatStream.cs +++ b/source/Cosmos.System2/FileSystem/FAT/FatStream.cs @@ -31,12 +31,7 @@ namespace Cosmos.System.FileSystem.FAT public FatStream(FatDirectoryEntry aEntry) { - if (aEntry == null) - { - throw new ArgumentNullException(nameof(aEntry)); - } - - mDirectoryEntry = aEntry; + mDirectoryEntry = aEntry ?? throw new ArgumentNullException(nameof(aEntry)); mFS = aEntry.GetFileSystem(); mFatTable = aEntry.GetFatTable(); mSize = aEntry.mSize; @@ -47,29 +42,11 @@ namespace Cosmos.System.FileSystem.FAT } } - public override bool CanSeek - { - get - { - return true; - } - } + public override bool CanSeek => true; - public override bool CanRead - { - get - { - return true; - } - } + public override bool CanRead => true; - public override bool CanWrite - { - get - { - return true; - } - } + public override bool CanWrite => true; public sealed override long Length { @@ -78,7 +55,7 @@ namespace Cosmos.System.FileSystem.FAT Global.mFileSystemDebugger.SendInternal("-- FatStream.get_Length --"); Global.mFileSystemDebugger.SendInternal("Length ="); Global.mFileSystemDebugger.SendInternal(mSize); - return (long)mSize; + return mSize; } } @@ -89,7 +66,7 @@ namespace Cosmos.System.FileSystem.FAT Global.mFileSystemDebugger.SendInternal("-- FatStream.get_Position --"); Global.mFileSystemDebugger.SendInternal("Position ="); Global.mFileSystemDebugger.SendInternal(mPosition); - return (long)mPosition; + return mPosition; } set { diff --git a/source/Cosmos.System2/FileSystem/FatFileSystemFactory.cs b/source/Cosmos.System2/FileSystem/FatFileSystemFactory.cs deleted file mode 100644 index 276b6bb53..000000000 --- a/source/Cosmos.System2/FileSystem/FatFileSystemFactory.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; - -using Cosmos.HAL.BlockDevice; -using Cosmos.System.FileSystem.FAT; - -namespace Cosmos.System.FileSystem -{ - public class FatFileSystemFactory : FileSystemFactory - { - public override string Name => "FAT"; - - public override bool IsType(Partition aDevice) - { - if (aDevice == null) - { - throw new ArgumentNullException(nameof(aDevice)); - } - - var xBPB = aDevice.NewBlockArray(1); - aDevice.ReadBlock(0UL, 1U, xBPB); - - var xSig = BitConverter.ToUInt16(xBPB, 510); - return xSig == 0xAA55; - } - - /// - /// Initializes a new instance of the class. - /// - /// The partition. - /// The root path. - /// FAT signature not found. - public override FileSystem Create(Partition aDevice, string aRootPath, long aSize) => new FatFileSystem(aDevice, aRootPath, aSize); - } -} diff --git a/source/Cosmos.System2/FileSystem/FileSystem.cs b/source/Cosmos.System2/FileSystem/FileSystem.cs index 411fa456f..578889335 100644 --- a/source/Cosmos.System2/FileSystem/FileSystem.cs +++ b/source/Cosmos.System2/FileSystem/FileSystem.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; -using System.IO; + using Cosmos.HAL.BlockDevice; -using Cosmos.System.FileSystem.FAT; using Cosmos.System.FileSystem.Listing; namespace Cosmos.System.FileSystem @@ -11,8 +10,8 @@ namespace Cosmos.System.FileSystem { protected FileSystem(Partition aDevice, string aRootPath, long aSize) { - Device = aDevice; - RootPath = aRootPath; + Device = aDevice ?? throw new ArgumentNullException(nameof(aDevice)); + RootPath = aRootPath ?? throw new ArgumentNullException(nameof(aRootPath)); Size = aSize; } diff --git a/source/Cosmos.System2/FileSystem/FileSystemFactory.cs b/source/Cosmos.System2/FileSystem/FileSystemFactory.cs index caae985df..0257b1730 100644 --- a/source/Cosmos.System2/FileSystem/FileSystemFactory.cs +++ b/source/Cosmos.System2/FileSystem/FileSystemFactory.cs @@ -1,4 +1,6 @@ -using Cosmos.HAL.BlockDevice; +using System; + +using Cosmos.HAL.BlockDevice; namespace Cosmos.System.FileSystem { @@ -15,6 +17,7 @@ namespace Cosmos.System.FileSystem /// The partition. /// Returns true if the file system can handle the partition, false otherwise. public abstract bool IsType(Partition aDevice); + /// /// Creates a new object for the given partition, root path, and size. /// @@ -23,5 +26,7 @@ namespace Cosmos.System.FileSystem /// The size, in MB. /// public abstract FileSystem Create(Partition aDevice, string aRootPath, long aSize); + + public virtual void Format(Partition partition) => throw new NotImplementedException(); } }