mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 04:18:43 +00:00
data structs
This commit is contained in:
parent
3d3f032d79
commit
03c9caf688
11 changed files with 478 additions and 255 deletions
82
source/Cosmos.System2/FileSystem/FAT/BiosParameterBlock.cs
Normal file
82
source/Cosmos.System2/FileSystem/FAT/BiosParameterBlock.cs
Normal file
|
|
@ -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<FatMediaKind, byte> MediaKind = new EnumField<FatMediaKind, byte>(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<Fat32ExtendedFlags, ushort> ExtendedFlags =
|
||||
new EnumField<Fat32ExtendedFlags, ushort>(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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
147
source/Cosmos.System2/FileSystem/FAT/DataStructures.cs
Normal file
147
source/Cosmos.System2/FileSystem/FAT/DataStructures.cs
Normal file
|
|
@ -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<T>(Field<T> field) => field.GetValue(Data);
|
||||
|
||||
public void SetValue<T>(Field<T> field, T value) => field.SetValue(Data, value);
|
||||
}
|
||||
|
||||
internal abstract class Field<T>
|
||||
{
|
||||
public Field(int position, int length)
|
||||
{
|
||||
Position = position;
|
||||
Length = length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Position, in bytes, of the field.
|
||||
/// </summary>
|
||||
public int Position { get; }
|
||||
/// <summary>
|
||||
/// Length, in bytes, of the field.
|
||||
/// </summary>
|
||||
public int Length { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value for this field from the data structure.
|
||||
/// </summary>
|
||||
/// <param name="data">A byte array which contains a data structure for which this field was defined.</param>
|
||||
/// <returns>The field value.</returns>
|
||||
public abstract T GetValue(byte[] data);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value for this field on the data structure.
|
||||
/// </summary>
|
||||
/// <param name="data">A byte array which contains a data structure for which this field was defined.</param>
|
||||
/// <param name="value">The value to set this field to.</param>
|
||||
public abstract void SetValue(byte[] data, T value);
|
||||
}
|
||||
|
||||
internal class ByteField : Field<byte>
|
||||
{
|
||||
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<ushort>
|
||||
{
|
||||
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<int>
|
||||
{
|
||||
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<uint>
|
||||
{
|
||||
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<string>
|
||||
{
|
||||
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<TEnum, TEnumUnderlyingType> : Field<TEnum>
|
||||
{
|
||||
private static readonly EnumField<Fat32ExtendedFlags, int> test = new EnumField<Fat32ExtendedFlags, int>(new Int32Field(12));
|
||||
|
||||
private readonly Field<TEnumUnderlyingType> _innerField;
|
||||
|
||||
public EnumField(Field<TEnumUnderlyingType> 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);
|
||||
}
|
||||
}
|
||||
11
source/Cosmos.System2/FileSystem/FAT/Fat32ExtendedFlags.cs
Normal file
11
source/Cosmos.System2/FileSystem/FAT/Fat32ExtendedFlags.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Cosmos.System.FileSystem.FAT
|
||||
{
|
||||
[Flags]
|
||||
internal enum Fat32ExtendedFlags
|
||||
{
|
||||
ActiveFatMask = 0x000F,
|
||||
Mirrored = 0x0080
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|||
/// <param name="aFatSector">The first sector of the FAT table.</param>
|
||||
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
|
|||
/// <exception cref="NotSupportedException">Can not get the FAT entry size for an unknown FAT type.</exception>
|
||||
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>();
|
||||
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
|
|||
/// <exception cref="Exception">Unknown file system type.</exception>
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The the EOF value for a specific FAT type.
|
||||
/// The EOF value for a specific FAT type.
|
||||
/// </summary>
|
||||
/// <returns>The EOF value.</returns>
|
||||
/// <exception cref="Exception">Unknown file system type.</exception>
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FatFileSystem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="aDevice">The partition.</param>
|
||||
/// <param name="aRootPath">The root path.</param>
|
||||
/// <exception cref="Exception">FAT signature not found.</exception>
|
||||
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();
|
||||
|
|
|
|||
54
source/Cosmos.System2/FileSystem/FAT/FatFileSystemFactory.cs
Normal file
54
source/Cosmos.System2/FileSystem/FAT/FatFileSystemFactory.cs
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FatFileSystem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="aDevice">The partition.</param>
|
||||
/// <param name="aRootPath">The root path.</param>
|
||||
/// <exception cref="Exception">FAT signature not found.</exception>
|
||||
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;
|
||||
}
|
||||
}
|
||||
10
source/Cosmos.System2/FileSystem/FAT/FatKind.cs
Normal file
10
source/Cosmos.System2/FileSystem/FAT/FatKind.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
namespace Cosmos.System.FileSystem.FAT
|
||||
{
|
||||
internal enum FatKind
|
||||
{
|
||||
Unkown,
|
||||
Fat12,
|
||||
Fat16,
|
||||
Fat32
|
||||
}
|
||||
}
|
||||
15
source/Cosmos.System2/FileSystem/FAT/FatMediaKind.cs
Normal file
15
source/Cosmos.System2/FileSystem/FAT/FatMediaKind.cs
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FatFileSystem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="aDevice">The partition.</param>
|
||||
/// <param name="aRootPath">The root path.</param>
|
||||
/// <exception cref="Exception">FAT signature not found.</exception>
|
||||
public override FileSystem Create(Partition aDevice, string aRootPath, long aSize) => new FatFileSystem(aDevice, aRootPath, aSize);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|||
/// <param name="aDevice">The partition.</param>
|
||||
/// <returns>Returns true if the file system can handle the partition, false otherwise.</returns>
|
||||
public abstract bool IsType(Partition aDevice);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="FileSystem"/> object for the given partition, root path, and size.
|
||||
/// </summary>
|
||||
|
|
@ -23,5 +26,7 @@ namespace Cosmos.System.FileSystem
|
|||
/// <param name="aSize">The size, in MB.</param>
|
||||
/// <returns></returns>
|
||||
public abstract FileSystem Create(Partition aDevice, string aRootPath, long aSize);
|
||||
|
||||
public virtual void Format(Partition partition) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue