[Aaru.Filesystems] Reformat and cleanup.

This commit is contained in:
2023-10-03 23:22:08 +01:00
parent 51f35c80d9
commit 7a608e0061
296 changed files with 21000 additions and 18286 deletions

View File

@@ -41,10 +41,16 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the AO-DOS filesystem</summary>
public sealed partial class AODOS : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.AODOS_Name;
/// <inheritdoc />
public Guid Id => new("668E5039-9DDD-442A-BE1B-A315D6E38E26");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -46,6 +46,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the AO-DOS filesystem</summary>
public sealed partial class AODOS
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -101,7 +103,7 @@ public sealed partial class AODOS
Bootable = true
};
sbInformation.AppendFormat(Localization._0_files_in_volume, bb.files).AppendLine();
sbInformation.AppendFormat(Localization._0_files_in_volume, bb.files).AppendLine();
sbInformation.AppendFormat(Localization._0_used_sectors_on_volume, bb.usedSectors).AppendLine();
sbInformation.AppendFormat(Localization.Disk_name_0, StringHandlers.CToString(bb.volumeLabel, encoding)).
@@ -109,4 +111,6 @@ public sealed partial class AODOS
information = sbInformation.ToString();
}
#endregion
}

View File

@@ -40,6 +40,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the AO-DOS filesystem</summary>
public sealed partial class AODOS
{
#region Nested type: BootBlock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct BootBlock
{
@@ -60,4 +62,6 @@ public sealed partial class AODOS
/// <summary>How many sectors are used</summary>
public readonly ushort usedSectors;
}
#endregion
}

View File

@@ -37,10 +37,16 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class APFS : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.APFS_Name;
/// <inheritdoc />
public Guid Id => new("A4060F9D-2909-42E2-9D95-DB31FA7EA797");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -41,6 +41,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class APFS
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -113,4 +115,6 @@ public sealed partial class APFS
Type = FS_TYPE
};
}
#endregion
}

View File

@@ -36,6 +36,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class APFS
{
#region Nested type: ContainerSuperBlock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct ContainerSuperBlock
{
@@ -47,4 +49,6 @@ public sealed partial class APFS
public readonly uint blockSize;
public readonly ulong containerBlocks;
}
#endregion
}

View File

@@ -35,8 +35,8 @@
<NoWarn>CS1591;CS1574</NoWarn>
</PropertyGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<InternalsVisibleTo Include="Aaru.Tests" />
<InternalsVisibleTo Include="Aaru.Tests.Devices" />
<InternalsVisibleTo Include="Aaru.Tests"/>
<InternalsVisibleTo Include="Aaru.Tests.Devices"/>
</ItemGroup>
<PropertyGroup>
<NrtRevisionFormat>$(Version)+{chash:8}</NrtRevisionFormat>
@@ -44,40 +44,40 @@
<NrtShowRevision>true</NrtShowRevision>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Claunia.Encoding" Version="1.9.2" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3" PrivateAssets="all" />
<PackageReference Include="Claunia.Encoding" Version="1.9.2"/>
<PackageReference Include="System.ValueTuple" Version="4.5.0"/>
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.3" PrivateAssets="all"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Aaru.Checksums\Aaru.Checksums.csproj" />
<ProjectReference Include="..\Aaru.CommonTypes\Aaru.CommonTypes.csproj" />
<ProjectReference Include="..\Aaru.Helpers\Aaru.Helpers.csproj" />
<ProjectReference Include="..\Aaru.Partitions\Aaru.Partitions.csproj" />
<ProjectReference Include="..\Aaru.Images\Aaru.Images.csproj" />
<ProjectReference Include="..\Aaru.Console\Aaru.Console.csproj" />
<ProjectReference Include="..\Aaru.Decoders\Aaru.Decoders.csproj" />
<ProjectReference Include="..\Aaru.Checksums\Aaru.Checksums.csproj"/>
<ProjectReference Include="..\Aaru.CommonTypes\Aaru.CommonTypes.csproj"/>
<ProjectReference Include="..\Aaru.Helpers\Aaru.Helpers.csproj"/>
<ProjectReference Include="..\Aaru.Partitions\Aaru.Partitions.csproj"/>
<ProjectReference Include="..\Aaru.Images\Aaru.Images.csproj"/>
<ProjectReference Include="..\Aaru.Console\Aaru.Console.csproj"/>
<ProjectReference Include="..\Aaru.Decoders\Aaru.Decoders.csproj"/>
</ItemGroup>
<ItemGroup>
<Folder Include="LisaFS\" />
<Folder Include="UCSDPascal\" />
<Folder Include="AppleMFS\" />
<Folder Include="CPM\" />
<Folder Include="AppleDOS\" />
<Folder Include="ISO9660\" />
<Folder Include="ISO9660\Structs\" />
<Folder Include="ISO9660\Consts\" />
<Folder Include="LisaFS\"/>
<Folder Include="UCSDPascal\"/>
<Folder Include="AppleMFS\"/>
<Folder Include="CPM\"/>
<Folder Include="AppleDOS\"/>
<Folder Include="ISO9660\"/>
<Folder Include="ISO9660\Structs\"/>
<Folder Include="ISO9660\Consts\"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\LICENSE.LGPL">
<Link>LICENSE.LGPL</Link>
</EmbeddedResource>
<EmbeddedResource Include="CPM\cpmdefs.json" />
<EmbeddedResource Include="CPM\cpmdefs.json"/>
<EmbeddedResource Update="Localization\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Aaru.Generators\Aaru.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\Aaru.Generators\Aaru.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup>
</Project>

View File

@@ -2,129 +2,129 @@
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve">
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=acorn/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=amigados/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=aodos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applecommon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=appledos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applehfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applehfsplus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applemfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=atheos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=bfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=btrfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cbm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cpm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cram/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dump/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ecma67/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=efs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=exfat/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ext2fs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=f2fs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=fat/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=fatx/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ffs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=fossil/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=hammer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=hpfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=hpofs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=iso9660/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=iso9660_005Cconsts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=iso9660_005Cstructs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=jfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=lif/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=lisafs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=localization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=locus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=microdos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=minixfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=nilfs2/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=nintendo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ntfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ods/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=opera/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pcengine/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pcfx/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=prodos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qnx4/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qnx6/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=rbf/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=refs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=reiser/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=reiser4/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=rt11/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=solarfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=squash/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sysv/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ucsdpascal/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=udf/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=unicos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=unixbfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vmfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vxfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=xfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=xia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=zfs/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=acorn/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=amigados/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=aodos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applecommon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=appledos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applehfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applehfsplus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=applemfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=atheos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=bfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=btrfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cbm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cpm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cram/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dump/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ecma67/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=efs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=exfat/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ext2fs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=f2fs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=fat/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=fatx/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ffs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=fossil/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=hammer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=hpfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=hpofs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=iso9660/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=iso9660_005Cconsts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=iso9660_005Cstructs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=jfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=lif/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=lisafs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=localization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=locus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=microdos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=minixfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=nilfs2/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=nintendo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ntfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ods/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=opera/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pcengine/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pcfx/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=prodos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qnx4/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=qnx6/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=rbf/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=refs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=reiser/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=reiser4/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=rt11/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=solarfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=squash/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sysv/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ucsdpascal/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=udf/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=unicos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=unixbfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vmfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=vxfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=xfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=xia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=zfs/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -35,11 +35,18 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Acorn's Advanced Data Filing System (ADFS)</summary>
public sealed partial class AcornADFS : IFilesystem
{
const string MODULE_NAME = "ADFS Plugin";
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.AcornADFS_Name;
/// <inheritdoc />
public Guid Id => new("BAFC1E50-9C64-4CD3-8400-80628CC27AFA");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
const string MODULE_NAME = "ADFS Plugin";
#endregion
}

View File

@@ -36,8 +36,8 @@ public sealed partial class AcornADFS
{
static byte AcornMapChecksum(byte[] data, int length)
{
int sum = 0;
int carry = 0;
var sum = 0;
var carry = 0;
if(length > data.Length)
length = data.Length;
@@ -101,7 +101,7 @@ public sealed partial class AcornADFS
length = data.Count;
// EOR r0, r1, r0, ROR #13
for(int i = 0; i < length; i++)
for(var i = 0; i < length; i++)
{
uint carry = sum & 0x1FFF;
sum >>= 13;
@@ -109,6 +109,6 @@ public sealed partial class AcornADFS
sum += carry << 19;
}
return (byte)(((sum & 0xFF000000) >> 24) ^ ((sum & 0xFF0000) >> 16) ^ ((sum & 0xFF00) >> 8) ^ (sum & 0xFF));
return (byte)((sum & 0xFF000000) >> 24 ^ (sum & 0xFF0000) >> 16 ^ (sum & 0xFF00) >> 8 ^ sum & 0xFF);
}
}

View File

@@ -41,6 +41,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Acorn's Advanced Data Filing System (ADFS)</summary>
public sealed partial class AcornADFS
{
#region IFilesystem Members
// TODO: BBC Master hard disks are untested...
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
@@ -77,7 +79,7 @@ public sealed partial class AcornADFS
OldMapSector1 oldMap1 = Marshal.ByteArrayToStructureLittleEndian<OldMapSector1>(sector);
AaruConsole.DebugWriteLine(MODULE_NAME, "oldMap0.checksum = {0}", oldMap0.checksum);
AaruConsole.DebugWriteLine(MODULE_NAME, "oldChk0 = {0}", oldChk0);
AaruConsole.DebugWriteLine(MODULE_NAME, "oldChk0 = {0}", oldChk0);
// According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400)
if(oldMap0.checksum == oldChk0 &&
@@ -89,14 +91,14 @@ public sealed partial class AcornADFS
if(errno != ErrorNumber.NoError)
return false;
byte[] tmp = new byte[256];
var tmp = new byte[256];
Array.Copy(sector, 256, tmp, 0, 256);
oldChk1 = AcornMapChecksum(tmp, 255);
oldMap1 = Marshal.ByteArrayToStructureLittleEndian<OldMapSector1>(tmp);
}
AaruConsole.DebugWriteLine(MODULE_NAME, "oldMap1.checksum = {0}", oldMap1.checksum);
AaruConsole.DebugWriteLine(MODULE_NAME, "oldChk1 = {0}", oldChk1);
AaruConsole.DebugWriteLine(MODULE_NAME, "oldChk1 = {0}", oldChk1);
if(oldMap0.checksum == oldChk0 &&
oldMap1.checksum == oldChk1 &&
@@ -116,7 +118,7 @@ public sealed partial class AcornADFS
if(sector.Length > OLD_DIRECTORY_SIZE)
{
byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
var tmp = new byte[OLD_DIRECTORY_SIZE];
Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
sector = tmp;
@@ -134,8 +136,8 @@ public sealed partial class AcornADFS
AaruConsole.DebugWriteLine(MODULE_NAME, "dirChk at 0x200 = {0}", dirChk);
if((oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC) ||
(oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC))
if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC ||
oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC)
return true;
// RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that...
@@ -152,7 +154,7 @@ public sealed partial class AcornADFS
if(sector.Length > OLD_DIRECTORY_SIZE)
{
byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
var tmp = new byte[OLD_DIRECTORY_SIZE];
Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
sector = tmp;
@@ -170,8 +172,8 @@ public sealed partial class AcornADFS
AaruConsole.DebugWriteLine(MODULE_NAME, "dirChk at 0x400 = {0}", dirChk);
if((oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC) ||
(oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC))
if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC ||
oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC)
return true;
}
}
@@ -185,7 +187,7 @@ public sealed partial class AcornADFS
return false;
byte newChk = NewMapChecksum(sector);
AaruConsole.DebugWriteLine(MODULE_NAME, "newChk = {0}", newChk);
AaruConsole.DebugWriteLine(MODULE_NAME, "newChk = {0}", newChk);
AaruConsole.DebugWriteLine(MODULE_NAME, "map.zoneChecksum = {0}", sector[0]);
sbSector = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize;
@@ -202,15 +204,15 @@ public sealed partial class AcornADFS
if(errno != ErrorNumber.NoError)
return false;
int bootChk = 0;
var bootChk = 0;
if(bootSector.Length < 512)
return false;
for(int i = 0; i < 0x1FF; i++)
for(var i = 0; i < 0x1FF; i++)
bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i];
AaruConsole.DebugWriteLine(MODULE_NAME, "bootChk = {0}", bootChk);
AaruConsole.DebugWriteLine(MODULE_NAME, "bootChk = {0}", bootChk);
AaruConsole.DebugWriteLine(MODULE_NAME, "bBlock.checksum = {0}", bootSector[0x1FF]);
if(newChk == sector[0] &&
@@ -227,10 +229,10 @@ public sealed partial class AcornADFS
else
return false;
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.log2secsize = {0}", drSb.log2secsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.idlen = {0}", drSb.idlen);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.log2secsize = {0}", drSb.log2secsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.idlen = {0}", drSb.idlen);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size_high = {0}", drSb.disc_size_high);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size = {0}", drSb.disc_size);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size = {0}", drSb.disc_size);
AaruConsole.DebugWriteLine(MODULE_NAME, "IsNullOrEmpty(drSb.reserved) = {0}",
ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved));
@@ -302,7 +304,7 @@ public sealed partial class AcornADFS
if(errno != ErrorNumber.NoError)
return;
byte[] tmp = new byte[256];
var tmp = new byte[256];
Array.Copy(sector, 256, tmp, 0, 256);
oldChk1 = AcornMapChecksum(tmp, 255);
oldMap1 = Marshal.ByteArrayToStructureLittleEndian<OldMapSector1>(tmp);
@@ -314,12 +316,12 @@ public sealed partial class AcornADFS
oldMap1.checksum != 0)
{
bytes = (ulong)((oldMap0.size[2] << 16) + (oldMap0.size[1] << 8) + oldMap0.size[0]) * 256;
byte[] namebytes = new byte[10];
var namebytes = new byte[10];
for(int i = 0; i < 5; i++)
for(var i = 0; i < 5; i++)
{
namebytes[i * 2] = oldMap0.name[i];
namebytes[(i * 2) + 1] = oldMap1.name[i];
namebytes[i * 2] = oldMap0.name[i];
namebytes[i * 2 + 1] = oldMap1.name[i];
}
metadata = new FileSystem
@@ -345,7 +347,7 @@ public sealed partial class AcornADFS
if(sector.Length > OLD_DIRECTORY_SIZE)
{
byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
var tmp = new byte[OLD_DIRECTORY_SIZE];
Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
sector = tmp;
@@ -372,7 +374,7 @@ public sealed partial class AcornADFS
if(sector.Length > OLD_DIRECTORY_SIZE)
{
byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
var tmp = new byte[OLD_DIRECTORY_SIZE];
Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
@@ -394,7 +396,7 @@ public sealed partial class AcornADFS
if(sector.Length > NEW_DIRECTORY_SIZE)
{
byte[] tmp = new byte[NEW_DIRECTORY_SIZE];
var tmp = new byte[NEW_DIRECTORY_SIZE];
Array.Copy(sector, 0, tmp, 0, NEW_DIRECTORY_SIZE - 41);
Array.Copy(sector, sector.Length - 42, tmp, NEW_DIRECTORY_SIZE - 42, 41);
@@ -414,7 +416,7 @@ public sealed partial class AcornADFS
sbInformation.AppendLine(Localization.Acorn_Advanced_Disc_Filing_System);
sbInformation.AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_per_sector, imagePlugin.Info.SectorSize).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_bytes, bytes).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_bytes, bytes).AppendLine();
sbInformation.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(namebytes, encoding)).
AppendLine();
@@ -443,7 +445,7 @@ public sealed partial class AcornADFS
return;
byte newChk = NewMapChecksum(sector);
AaruConsole.DebugWriteLine(MODULE_NAME, "newChk = {0}", newChk);
AaruConsole.DebugWriteLine(MODULE_NAME, "newChk = {0}", newChk);
AaruConsole.DebugWriteLine(MODULE_NAME, "map.zoneChecksum = {0}", sector[0]);
sbSector = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize;
@@ -457,12 +459,12 @@ public sealed partial class AcornADFS
if(errno != ErrorNumber.NoError)
return;
int bootChk = 0;
var bootChk = 0;
for(int i = 0; i < 0x1FF; i++)
for(var i = 0; i < 0x1FF; i++)
bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i];
AaruConsole.DebugWriteLine(MODULE_NAME, "bootChk = {0}", bootChk);
AaruConsole.DebugWriteLine(MODULE_NAME, "bootChk = {0}", bootChk);
AaruConsole.DebugWriteLine(MODULE_NAME, "bBlock.checksum = {0}", bootSector[0x1FF]);
if(newChk == sector[0] &&
@@ -480,29 +482,29 @@ public sealed partial class AcornADFS
return;
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.log2secsize = {0}", drSb.log2secsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.spt = {0}", drSb.spt);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.heads = {0}", drSb.heads);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.density = {0}", drSb.density);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.idlen = {0}", drSb.idlen);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.log2bpmb = {0}", drSb.log2bpmb);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.skew = {0}", drSb.skew);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.bootoption = {0}", drSb.bootoption);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.lowsector = {0}", drSb.lowsector);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.nzones = {0}", drSb.nzones);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.zone_spare = {0}", drSb.zone_spare);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.root = {0}", drSb.root);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size = {0}", drSb.disc_size);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_id = {0}", drSb.disc_id);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.spt = {0}", drSb.spt);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.heads = {0}", drSb.heads);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.density = {0}", drSb.density);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.idlen = {0}", drSb.idlen);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.log2bpmb = {0}", drSb.log2bpmb);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.skew = {0}", drSb.skew);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.bootoption = {0}", drSb.bootoption);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.lowsector = {0}", drSb.lowsector);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.nzones = {0}", drSb.nzones);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.zone_spare = {0}", drSb.zone_spare);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.root = {0}", drSb.root);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size = {0}", drSb.disc_size);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_id = {0}", drSb.disc_id);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_name = {0}",
StringHandlers.CToString(drSb.disc_name, encoding));
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_type = {0}", drSb.disc_type);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_type = {0}", drSb.disc_type);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.disc_size_high = {0}", drSb.disc_size_high);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.flags = {0}", drSb.flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.nzones_high = {0}", drSb.nzones_high);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.flags = {0}", drSb.flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.nzones_high = {0}", drSb.nzones_high);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.format_version = {0}", drSb.format_version);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.root_size = {0}", drSb.root_size);
AaruConsole.DebugWriteLine(MODULE_NAME, "drSb.root_size = {0}", drSb.root_size);
if(drSb.log2secsize is < 8 or > 10)
return;
@@ -532,20 +534,20 @@ public sealed partial class AcornADFS
sbInformation.AppendLine(Localization.Acorn_Advanced_Disc_Filing_System);
sbInformation.AppendLine();
sbInformation.AppendFormat(Localization.Version_0, drSb.format_version).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_per_sector, 1 << drSb.log2secsize).AppendLine();
sbInformation.AppendFormat(Localization.Version_0, drSb.format_version).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_per_sector, 1 << drSb.log2secsize).AppendLine();
sbInformation.AppendFormat(Localization._0_sectors_per_track, drSb.spt).AppendLine();
sbInformation.AppendFormat(Localization._0_heads, drSb.heads).AppendLine();
sbInformation.AppendFormat(Localization.Density_code_0, drSb.density).AppendLine();
sbInformation.AppendFormat(Localization.Skew_0, drSb.skew).AppendLine();
sbInformation.AppendFormat(Localization.Boot_option_0, drSb.bootoption).AppendLine();
sbInformation.AppendFormat(Localization._0_heads, drSb.heads).AppendLine();
sbInformation.AppendFormat(Localization.Density_code_0, drSb.density).AppendLine();
sbInformation.AppendFormat(Localization.Skew_0, drSb.skew).AppendLine();
sbInformation.AppendFormat(Localization.Boot_option_0, drSb.bootoption).AppendLine();
// TODO: What the hell is this field refering to?
sbInformation.AppendFormat(Localization.Root_starts_at_frag_0, drSb.root).AppendLine();
//sbInformation.AppendFormat("Root is {0} bytes long", drSb.root_size).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_bytes_in_1_zones, bytes, zones).AppendLine();
sbInformation.AppendFormat(Localization.Volume_flags_0_X4, drSb.flags).AppendLine();
sbInformation.AppendFormat(Localization.Volume_flags_0_X4, drSb.flags).AppendLine();
if(drSb.disc_id > 0)
{
@@ -567,4 +569,6 @@ public sealed partial class AcornADFS
metadata.ClusterSize = (uint)(1 << drSb.log2secsize);
metadata.Type = FS_TYPE;
}
#endregion
}

View File

@@ -34,6 +34,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Acorn's Advanced Data Filing System (ADFS)</summary>
public sealed partial class AcornADFS
{
#region Nested type: BootBlock
/// <summary>Boot block, used in hard disks and ADFS-F and higher.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct BootBlock
@@ -46,6 +48,40 @@ public sealed partial class AcornADFS
public readonly byte checksum;
}
#endregion
#region Nested type: DirectoryEntry
/// <summary>Directory header, common to "old" and "new" directories</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryEntry
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public readonly byte[] name;
public readonly uint load;
public readonly uint exec;
public readonly uint length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] address;
public readonly byte atts;
}
#endregion
#region Nested type: DirectoryHeader
/// <summary>Directory header, common to "old" and "new" directories</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryHeader
{
public readonly byte masterSequence;
public readonly uint magic;
}
#endregion
#region Nested type: DiscRecord
/// <summary>Disc record, used in hard disks and ADFS-E and higher.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DiscRecord
@@ -76,65 +112,23 @@ public sealed partial class AcornADFS
public readonly byte[] reserved;
}
/// <summary>Free block map, sector 0, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D</summary>
#endregion
#region Nested type: NewDirectory
/// <summary>Directory, new format</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct OldMapSector0
readonly struct NewDirectory
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)]
public readonly byte[] freeStart;
public readonly byte reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public readonly byte[] name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] size;
public readonly byte checksum;
public readonly DirectoryHeader header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 77)]
public readonly DirectoryEntry[] entries;
public readonly NewDirectoryTail tail;
}
/// <summary>Free block map, sector 1, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct OldMapSector1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)]
public readonly byte[] freeStart;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public readonly byte[] name;
public readonly ushort discId;
public readonly byte boot;
public readonly byte freeEnd;
public readonly byte checksum;
}
#endregion
/// <summary>Free block map, sector 0, used in ADFS-E</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct NewMap
{
public readonly byte zoneChecksum;
public readonly ushort freeLink;
public readonly byte crossChecksum;
public readonly DiscRecord discRecord;
}
/// <summary>Directory header, common to "old" and "new" directories</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryHeader
{
public readonly byte masterSequence;
public readonly uint magic;
}
/// <summary>Directory header, common to "old" and "new" directories</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryEntry
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public readonly byte[] name;
public readonly uint load;
public readonly uint exec;
public readonly uint length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] address;
public readonly byte atts;
}
#region Nested type: NewDirectoryTail
/// <summary>Directory tail, new format</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
@@ -153,6 +147,38 @@ public sealed partial class AcornADFS
public readonly byte checkByte;
}
#endregion
#region Nested type: NewMap
/// <summary>Free block map, sector 0, used in ADFS-E</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct NewMap
{
public readonly byte zoneChecksum;
public readonly ushort freeLink;
public readonly byte crossChecksum;
public readonly DiscRecord discRecord;
}
#endregion
#region Nested type: OldDirectory
/// <summary>Directory, old format</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct OldDirectory
{
public readonly DirectoryHeader header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 47)]
public readonly DirectoryEntry[] entries;
public readonly OldDirectoryTail tail;
}
#endregion
#region Nested type: OldDirectoryTail
/// <summary>Directory tail, old format</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct OldDirectoryTail
@@ -171,23 +197,41 @@ public sealed partial class AcornADFS
public readonly byte checkByte;
}
/// <summary>Directory, old format</summary>
#endregion
#region Nested type: OldMapSector0
/// <summary>Free block map, sector 0, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct OldDirectory
readonly struct OldMapSector0
{
public readonly DirectoryHeader header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 47)]
public readonly DirectoryEntry[] entries;
public readonly OldDirectoryTail tail;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)]
public readonly byte[] freeStart;
public readonly byte reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public readonly byte[] name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] size;
public readonly byte checksum;
}
/// <summary>Directory, new format</summary>
#endregion
#region Nested type: OldMapSector1
/// <summary>Free block map, sector 1, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct NewDirectory
readonly struct OldMapSector1
{
public readonly DirectoryHeader header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 77)]
public readonly DirectoryEntry[] entries;
public readonly NewDirectoryTail tail;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)]
public readonly byte[] freeStart;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public readonly byte[] name;
public readonly ushort discId;
public readonly byte boot;
public readonly byte freeEnd;
public readonly byte checksum;
}
#endregion
}

View File

@@ -35,11 +35,18 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Amiga Fast File System (AFFS)</summary>
public sealed partial class AmigaDOSPlugin : IFilesystem
{
const string MODULE_NAME = "AmigaDOS plugin";
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.AmigaDOSPlugin_Name;
/// <inheritdoc />
public Guid Id => new("3c882400-208c-427d-a086-9119852a1bc7");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
const string MODULE_NAME = "AmigaDOS plugin";
#endregion
}

View File

@@ -37,14 +37,14 @@ public sealed partial class AmigaDOSPlugin
{
static RootBlock MarshalRootBlock(byte[] block)
{
byte[] tmp = new byte[228];
Array.Copy(block, 0, tmp, 0, 24);
var tmp = new byte[228];
Array.Copy(block, 0, tmp, 0, 24);
Array.Copy(block, block.Length - 200, tmp, 28, 200);
RootBlock root = Marshal.ByteArrayToStructureBigEndian<RootBlock>(tmp);
root.hashTable = new uint[(block.Length - 224) / 4];
for(int i = 0; i < root.hashTable.Length; i++)
root.hashTable[i] = BigEndianBitConverter.ToUInt32(block, 24 + (i * 4));
for(var i = 0; i < root.hashTable.Length; i++)
root.hashTable[i] = BigEndianBitConverter.ToUInt32(block, 24 + i * 4);
return root;
}
@@ -53,7 +53,7 @@ public sealed partial class AmigaDOSPlugin
{
uint sum = 0;
for(int i = 0; i < data.Length; i += 4)
for(var i = 0; i < data.Length; i += 4)
sum += (uint)((data[i] << 24) + (data[i + 1] << 16) + (data[i + 2] << 8) + data[i + 3]);
return (uint)-sum;
@@ -63,7 +63,7 @@ public sealed partial class AmigaDOSPlugin
{
uint sum = 0;
for(int i = 0; i < data.Length; i += 4)
for(var i = 0; i < data.Length; i += 4)
{
uint psum = sum;

View File

@@ -43,6 +43,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Amiga Fast File System (AFFS)</summary>
public sealed partial class AmigaDOSPlugin
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -87,7 +89,7 @@ public sealed partial class AmigaDOSPlugin
uint bsum = AmigaBootChecksum(sector);
AaruConsole.DebugWriteLine(MODULE_NAME, "bblk.checksum = 0x{0:X8}", bblk.checksum);
AaruConsole.DebugWriteLine(MODULE_NAME, "bsum = 0x{0:X8}", bsum);
AaruConsole.DebugWriteLine(MODULE_NAME, "bsum = 0x{0:X8}", bsum);
ulong bRootPtr = 0;
@@ -100,10 +102,10 @@ public sealed partial class AmigaDOSPlugin
ulong[] rootPtrs =
{
bRootPtr + partition.Start, ((partition.End - partition.Start + 1) / 2) + partition.Start - 2,
((partition.End - partition.Start + 1) / 2) + partition.Start - 1,
((partition.End - partition.Start + 1) / 2) + partition.Start,
((partition.End - partition.Start + 1) / 2) + partition.Start + 4
bRootPtr + partition.Start, (partition.End - partition.Start + 1) / 2 + partition.Start - 2,
(partition.End - partition.Start + 1) / 2 + partition.Start - 1,
(partition.End - partition.Start + 1) / 2 + partition.Start,
(partition.End - partition.Start + 1) / 2 + partition.Start + 4
};
var rblk = new RootBlock();
@@ -129,9 +131,9 @@ public sealed partial class AmigaDOSPlugin
AaruConsole.DebugWriteLine(MODULE_NAME, "rblk.hashTableSize = {0}", rblk.hashTableSize);
uint blockSize = (rblk.hashTableSize + 56) * 4;
uint sectorsPerBlock = (uint)(blockSize / sector.Length);
var sectorsPerBlock = (uint)(blockSize / sector.Length);
AaruConsole.DebugWriteLine(MODULE_NAME, "blockSize = {0}", blockSize);
AaruConsole.DebugWriteLine(MODULE_NAME, "blockSize = {0}", blockSize);
AaruConsole.DebugWriteLine(MODULE_NAME, "sectorsPerBlock = {0}", sectorsPerBlock);
if(blockSize % sector.Length > 0)
@@ -151,7 +153,7 @@ public sealed partial class AmigaDOSPlugin
uint rsum = AmigaChecksum(sector);
AaruConsole.DebugWriteLine(MODULE_NAME, "rblk.checksum = 0x{0:X8}", rblk.checksum);
AaruConsole.DebugWriteLine(MODULE_NAME, "rsum = 0x{0:X8}", rsum);
AaruConsole.DebugWriteLine(MODULE_NAME, "rsum = 0x{0:X8}", rsum);
rblk.sec_type = BigEndianBitConverter.ToUInt32(sector, sector.Length - 4);
AaruConsole.DebugWriteLine(MODULE_NAME, "rblk.sec_type = {0}", rblk.sec_type);
@@ -194,16 +196,16 @@ public sealed partial class AmigaDOSPlugin
ulong[] rootPtrs =
{
bRootPtr + partition.Start, ((partition.End - partition.Start + 1) / 2) + partition.Start - 2,
((partition.End - partition.Start + 1) / 2) + partition.Start - 1,
((partition.End - partition.Start + 1) / 2) + partition.Start,
((partition.End - partition.Start + 1) / 2) + partition.Start + 4
bRootPtr + partition.Start, (partition.End - partition.Start + 1) / 2 + partition.Start - 2,
(partition.End - partition.Start + 1) / 2 + partition.Start - 1,
(partition.End - partition.Start + 1) / 2 + partition.Start,
(partition.End - partition.Start + 1) / 2 + partition.Start + 4
};
var rootBlk = new RootBlock();
byte[] rootBlockSector = null;
bool rootFound = false;
var rootFound = false;
uint blockSize = 0;
// So to handle even number of sectors
@@ -227,9 +229,9 @@ public sealed partial class AmigaDOSPlugin
AaruConsole.DebugWriteLine(MODULE_NAME, "rootBlk.hashTableSize = {0}", rootBlk.hashTableSize);
blockSize = (rootBlk.hashTableSize + 56) * 4;
uint sectorsPerBlock = (uint)(blockSize / rootBlockSector.Length);
var sectorsPerBlock = (uint)(blockSize / rootBlockSector.Length);
AaruConsole.DebugWriteLine(MODULE_NAME, "blockSize = {0}", blockSize);
AaruConsole.DebugWriteLine(MODULE_NAME, "blockSize = {0}", blockSize);
AaruConsole.DebugWriteLine(MODULE_NAME, "sectorsPerBlock = {0}", sectorsPerBlock);
if(blockSize % rootBlockSector.Length > 0)
@@ -249,7 +251,7 @@ public sealed partial class AmigaDOSPlugin
uint rsum = AmigaChecksum(rootBlockSector);
AaruConsole.DebugWriteLine(MODULE_NAME, "rootBlk.checksum = 0x{0:X8}", rootBlk.checksum);
AaruConsole.DebugWriteLine(MODULE_NAME, "rsum = 0x{0:X8}", rsum);
AaruConsole.DebugWriteLine(MODULE_NAME, "rsum = 0x{0:X8}", rsum);
rootBlk.sec_type = BigEndianBitConverter.ToUInt32(rootBlockSector, rootBlockSector.Length - 4);
AaruConsole.DebugWriteLine(MODULE_NAME, "rootBlk.sec_type = {0}", rootBlk.sec_type);
@@ -339,8 +341,10 @@ public sealed partial class AmigaDOSPlugin
if(rootBlk.bitmapExtensionBlock != 0x00000000 &&
rootBlk.bitmapExtensionBlock != 0xFFFFFFFF)
{
sbInformation.AppendFormat(Localization.Bitmap_extension_at_block_0, rootBlk.bitmapExtensionBlock).
AppendLine();
}
if((bootBlk.diskType & 0xFF) == 4 ||
(bootBlk.diskType & 0xFF) == 5)
@@ -349,7 +353,7 @@ public sealed partial class AmigaDOSPlugin
ulong blocks = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / blockSize;
sbInformation.AppendFormat(Localization.Volume_block_size_is_0_bytes, blockSize).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_blocks, blocks).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_blocks, blocks).AppendLine();
sbInformation.AppendFormat(Localization.Volume_created_on_0,
DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks)).
@@ -379,4 +383,6 @@ public sealed partial class AmigaDOSPlugin
// Useful as a serial
metadata.VolumeSerial = $"{rootBlk.checksum:X8}";
}
#endregion
}

View File

@@ -34,6 +34,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Amiga Fast File System (AFFS)</summary>
public sealed partial class AmigaDOSPlugin
{
#region Nested type: BootBlock
/// <summary>Boot block, first 2 sectors</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct BootBlock
@@ -49,6 +51,10 @@ public sealed partial class AmigaDOSPlugin
public byte[] bootCode;
}
#endregion
#region Nested type: RootBlock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct RootBlock
{
@@ -113,4 +119,6 @@ public sealed partial class AmigaDOSPlugin
/// <summary>Offset 0x18+hashTableSize*4+196, block secondary type = ST_ROOT (1)</summary>
public uint sec_type;
}
#endregion
}

View File

@@ -36,21 +36,33 @@ namespace Aaru.Filesystems;
// https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf
static partial class AppleCommon
{
#region Nested type: ExtendedFinderFlags
[Flags]
internal enum VolumeAttributes : ushort
internal enum ExtendedFinderFlags : ushort
{
HardwareLock = 0x80, Unmounted = 0x100, SparedBadBlocks = 0x200,
DoesNotNeedCache = 0x400, BootInconsistent = 0x800, ReusedIds = 0x1000,
Journaled = 0x2000, Inconsistent = 0x4000, SoftwareLock = 0x8000
/// <summary>If set the other extended flags are ignored.</summary>
kExtendedFlagsAreInvalid = 0x8000,
/// <summary>Set if the file or folder has a badge resource.</summary>
kExtendedFlagHasCustomBadge = 0x0100,
/// <summary>Set if the object is marked as busy/incomplete.</summary>
kExtendedFlagObjectIsBusy = 0x0080,
/// <summary>Set if the file contains routing info resource.</summary>
kExtendedFlagHasRoutingInfo = 0x0004
}
#endregion
#region Nested type: FinderFlags
[Flags]
internal enum FinderFlags : ushort
{
/// <summary>Is on desktop.</summary>
kIsOnDesk = 0x0001,
/// <summary>Color mask.</summary>
kColor = 0x000E, kRequireSwitchLaunch = 0x0020,
kColor = 0x000E,
kRequireSwitchLaunch = 0x0020,
/// <summary>If clear, the application needs to write to its resource fork, and therefore cannot be shared on a server.</summary>
kIsShared = 0x0040,
/// <summary>Extension or control panel with no INIT entries in resource fork.</summary>
@@ -61,7 +73,8 @@ static partial class AppleCommon
/// </summary>
kHasBeenInited = 0x0100,
/// <summary>PowerTalk</summary>
kAOCE = 0x200, kChanged = 0x0200,
kAOCE = 0x200,
kChanged = 0x0200,
/// <summary>Has a custom icon in the resource fork.</summary>
kHasCustomIcon = 0x0400,
/// <summary>Is a stationery.</summary>
@@ -76,21 +89,34 @@ static partial class AppleCommon
kIsAlias = 0x8000
}
#endregion
#region Nested type: FinderFolder
internal enum FinderFolder : short
{
fTrash = -3, fDesktop = -2, fDisk = 0
fTrash = -3,
fDesktop = -2,
fDisk = 0
}
#endregion
#region Nested type: VolumeAttributes
[Flags]
internal enum ExtendedFinderFlags : ushort
internal enum VolumeAttributes : ushort
{
/// <summary>If set the other extended flags are ignored.</summary>
kExtendedFlagsAreInvalid = 0x8000,
/// <summary>Set if the file or folder has a badge resource.</summary>
kExtendedFlagHasCustomBadge = 0x0100,
/// <summary>Set if the object is marked as busy/incomplete.</summary>
kExtendedFlagObjectIsBusy = 0x0080,
/// <summary>Set if the file contains routing info resource.</summary>
kExtendedFlagHasRoutingInfo = 0x0004
HardwareLock = 0x80,
Unmounted = 0x100,
SparedBadBlocks = 0x200,
DoesNotNeedCache = 0x400,
BootInconsistent = 0x800,
ReusedIds = 0x1000,
Journaled = 0x2000,
Inconsistent = 0x4000,
SoftwareLock = 0x8000
}
#endregion
}

View File

@@ -58,9 +58,12 @@ static partial class AppleCommon
sb.AppendLine(Localization.Boot_block_should_be_executed);
if((bb.bbVersion & 0x2000) > 0)
{
sb.
AppendFormat(Localization.System_heap_will_be_extended_by_0_bytes_and_a_1_fraction_of_the_available_RAM,
bb.bbSysHeapExtra, bb.bbSysHeapFract).AppendLine();
AppendFormat(
Localization.System_heap_will_be_extended_by_0_bytes_and_a_1_fraction_of_the_available_RAM,
bb.bbSysHeapExtra, bb.bbSysHeapFract).AppendLine();
}
}
}
else if((bb.bbVersion & 0xFF) == 0x0D)
@@ -99,10 +102,10 @@ static partial class AppleCommon
sb.AppendFormat(Localization.Clipboard_filename_0, StringHandlers.PascalToString(bb.bbScrapName, encoding)).
AppendLine();
sb.AppendFormat(Localization.Maximum_opened_files_0, bb.bbCntFCBs * 4).AppendLine();
sb.AppendFormat(Localization.Event_queue_size_0, bb.bbCntEvts).AppendLine();
sb.AppendFormat(Localization.Heap_size_with_128KiB_of_RAM_0_bytes, bb.bb128KSHeap).AppendLine();
sb.AppendFormat(Localization.Heap_size_with_256KiB_of_RAM_0_bytes, bb.bb256KSHeap).AppendLine();
sb.AppendFormat(Localization.Maximum_opened_files_0, bb.bbCntFCBs * 4).AppendLine();
sb.AppendFormat(Localization.Event_queue_size_0, bb.bbCntEvts).AppendLine();
sb.AppendFormat(Localization.Heap_size_with_128KiB_of_RAM_0_bytes, bb.bb128KSHeap).AppendLine();
sb.AppendFormat(Localization.Heap_size_with_256KiB_of_RAM_0_bytes, bb.bb256KSHeap).AppendLine();
sb.AppendFormat(Localization.Heap_size_with_512KiB_of_RAM_or_more_0_bytes, bb.bbSysHeapSize).AppendLine();
return sb.ToString();

View File

@@ -36,6 +36,8 @@ namespace Aaru.Filesystems;
// https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf
static partial class AppleCommon
{
#region Nested type: BootBlock
/// <summary>Should be sectors 0 and 1 in volume, followed by boot code</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct BootBlock // Should be sectors 0 and 1 in volume
@@ -87,20 +89,44 @@ static partial class AppleCommon
public readonly uint bbSysHeapFract;
}
internal struct Rect
#endregion
#region Nested type: DInfo
internal struct DInfo
{
public ushort top;
public ushort left;
public ushort bottom;
public ushort right;
/// <summary>Position and dimensions of the folder's window.</summary>
public Rect frRect;
/// <summary>Flags.</summary>
public FinderFlags frFlags;
/// <summary>Folder's location in the parent folder.</summary>
public Point frLocation;
/// <summary>Finder view selected for folder.</summary>
public ushort frView;
}
internal struct Point
#endregion
#region Nested type: DXInfo
internal struct DXInfo
{
public ushort v;
public ushort h;
/// <summary>Scroll position for icon views.</summary>
public Point frScroll;
/// <summary>Directory ID chain of open folders.</summary>
public uint frOpenChain;
/// <summary>Extended flags. If high-bit is set, most significant byte is script code and least significant byte are flags.</summary>
public ExtendedFinderFlags frXFlags;
/// <summary>Resource fork ID of directory comment if high bit is clear.</summary>
public ushort frComment;
/// <summary>Put away folder ID.</summary>
public uint frPutAway;
}
#endregion
#region Nested type: FInfo
internal struct FInfo
{
/// <summary>The type of the file.</summary>
@@ -115,6 +141,10 @@ static partial class AppleCommon
public FinderFolder fdFldr;
}
#endregion
#region Nested type: FXInfo
internal struct FXInfo
{
/// <summary>Resource fork ID of file icon.</summary>
@@ -129,29 +159,27 @@ static partial class AppleCommon
public uint fdPutAway;
}
internal struct DInfo
#endregion
#region Nested type: Point
internal struct Point
{
/// <summary>Position and dimensions of the folder's window.</summary>
public Rect frRect;
/// <summary>Flags.</summary>
public FinderFlags frFlags;
/// <summary>Folder's location in the parent folder.</summary>
public Point frLocation;
/// <summary>Finder view selected for folder.</summary>
public ushort frView;
public ushort v;
public ushort h;
}
internal struct DXInfo
#endregion
#region Nested type: Rect
internal struct Rect
{
/// <summary>Scroll position for icon views.</summary>
public Point frScroll;
/// <summary>Directory ID chain of open folders.</summary>
public uint frOpenChain;
/// <summary>Extended flags. If high-bit is set, most significant byte is script code and least significant byte are flags.</summary>
public ExtendedFinderFlags frXFlags;
/// <summary>Resource fork ID of directory comment if high bit is clear.</summary>
public ushort frComment;
/// <summary>Put away folder ID.</summary>
public uint frPutAway;
public ushort top;
public ushort left;
public ushort bottom;
public ushort right;
}
#endregion
}

View File

@@ -53,12 +53,17 @@ public sealed partial class AppleDOS : IReadOnlyFilesystem
uint _usedSectors;
Vtoc _vtoc;
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public FileSystem Metadata { get; private set; }
/// <inheritdoc />
public string Name => Localization.AppleDOS_Name;
/// <inheritdoc />
public Guid Id => new("8658A1E9-B2E7-4BCC-9638-157A31B0A700\n");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
@@ -69,14 +74,15 @@ public sealed partial class AppleDOS : IReadOnlyFilesystem
/// <inheritdoc />
public Dictionary<string, string> Namespaces => null;
#endregion
static Dictionary<string, string> GetDefaultOptions() => new()
{
{
"debug", false.ToString()
}
{ "debug", false.ToString() }
};
#region Caches
#region Caches
/// <summary>Caches track/sector lists</summary>
Dictionary<string, byte[]> _extentCache;
/// <summary>Caches files</summary>
@@ -95,5 +101,6 @@ public sealed partial class AppleDOS : IReadOnlyFilesystem
Dictionary<string, byte> _fileTypeCache;
/// <summary>Caches locked files</summary>
List<string> _lockedFiles;
#endregion Caches
#endregion Caches
}

View File

@@ -42,6 +42,8 @@ namespace Aaru.Filesystems;
public sealed partial class AppleDOS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber ReadLink(string path, out string dest)
{
@@ -62,7 +64,7 @@ public sealed partial class AppleDOS
string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0)
return ErrorNumber.NotSupported;
List<string> contents = _catalogCache.Keys.ToList();
var contents = _catalogCache.Keys.ToList();
if(_debug)
{
@@ -117,10 +119,12 @@ public sealed partial class AppleDOS
return ErrorNumber.NoError;
}
#endregion
ErrorNumber ReadCatalog()
{
var catalogMs = new MemoryStream();
ulong lba = (ulong)((_vtoc.catalogTrack * _sectorsPerTrack) + _vtoc.catalogSector);
var catalogMs = new MemoryStream();
var lba = (ulong)(_vtoc.catalogTrack * _sectorsPerTrack + _vtoc.catalogSector);
_totalFileEntries = 0;
_catalogCache = new Dictionary<string, ushort>();
_fileTypeCache = new Dictionary<string, byte>();
@@ -151,11 +155,11 @@ public sealed partial class AppleDOS
_track1UsedByFiles |= entry.extentTrack == 1;
_track2UsedByFiles |= entry.extentTrack == 2;
byte[] filenameB = new byte[30];
ushort ts = (ushort)((entry.extentTrack << 8) | entry.extentSector);
var filenameB = new byte[30];
var ts = (ushort)(entry.extentTrack << 8 | entry.extentSector);
// Apple DOS has high byte set over ASCII.
for(int i = 0; i < 30; i++)
for(var i = 0; i < 30; i++)
filenameB[i] = (byte)(entry.filename[i] & 0x7F);
string filename = StringHandlers.SpacePaddedToString(filenameB, _encoding);
@@ -171,7 +175,7 @@ public sealed partial class AppleDOS
_lockedFiles.Add(filename);
}
lba = (ulong)((catSector.trackOfNext * _sectorsPerTrack) + catSector.sectorOfNext);
lba = (ulong)(catSector.trackOfNext * _sectorsPerTrack + catSector.sectorOfNext);
if(lba > _device.Info.Sectors)
break;

View File

@@ -40,6 +40,8 @@ namespace Aaru.Filesystems;
public sealed partial class AppleDOS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber GetAttributes(string path, out FileAttributes attributes)
{
@@ -48,10 +50,7 @@ public sealed partial class AppleDOS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -67,7 +66,7 @@ public sealed partial class AppleDOS
if(_lockedFiles.Contains(filename))
attributes |= FileAttributes.ReadOnly;
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0))
attributes |= FileAttributes.System;
@@ -82,10 +81,7 @@ public sealed partial class AppleDOS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -96,15 +92,17 @@ public sealed partial class AppleDOS
if(filename.Length > 30)
return ErrorNumber.NameTooLong;
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0))
{
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0)
file = _catalogBlocks;
else if(string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)
file = _vtocBlocks;
else
file = _bootBlocks;
}
else
{
if(!_fileCache.TryGetValue(filename, out file))
@@ -179,10 +177,7 @@ public sealed partial class AppleDOS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -200,7 +195,7 @@ public sealed partial class AppleDOS
_fileSizeCache.TryGetValue(filename, out int fileSize);
GetAttributes(path, out FileAttributes attrs);
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0))
{
@@ -226,12 +221,11 @@ public sealed partial class AppleDOS
return ErrorNumber.NoError;
}
#endregion
ErrorNumber CacheFile(string path)
{
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -244,7 +238,7 @@ public sealed partial class AppleDOS
if(!_catalogCache.TryGetValue(filename, out ushort ts))
return ErrorNumber.NoSuchFile;
ulong lba = (ulong)((((ts & 0xFF00) >> 8) * _sectorsPerTrack) + (ts & 0xFF));
var lba = (ulong)(((ts & 0xFF00) >> 8) * _sectorsPerTrack + (ts & 0xFF));
var fileMs = new MemoryStream();
var tsListMs = new MemoryStream();
ushort expectedBlock = 0;
@@ -265,7 +259,7 @@ public sealed partial class AppleDOS
if(tsSector.sectorOffset > expectedBlock)
{
byte[] hole = new byte[(tsSector.sectorOffset - expectedBlock) * _vtoc.bytesPerSector];
var hole = new byte[(tsSector.sectorOffset - expectedBlock) * _vtoc.bytesPerSector];
fileMs.Write(hole, 0, hole.Length);
expectedBlock = tsSector.sectorOffset;
}
@@ -276,7 +270,7 @@ public sealed partial class AppleDOS
_track2UsedByFiles |= entry.track == 2;
_usedSectors++;
ulong blockLba = (ulong)((entry.track * _sectorsPerTrack) + entry.sector);
var blockLba = (ulong)(entry.track * _sectorsPerTrack + entry.sector);
if(blockLba == 0)
break;
@@ -290,7 +284,7 @@ public sealed partial class AppleDOS
expectedBlock++;
}
lba = (ulong)((tsSector.nextListTrack * _sectorsPerTrack) + tsSector.nextListSector);
lba = (ulong)(tsSector.nextListTrack * _sectorsPerTrack + tsSector.nextListSector);
}
if(_fileCache.ContainsKey(filename))

View File

@@ -37,6 +37,8 @@ namespace Aaru.Filesystems;
public sealed partial class AppleDOS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -85,13 +87,14 @@ public sealed partial class AppleDOS
AppendLine();
sb.AppendFormat(Localization.File_system_initialized_by_DOS_release_0, _vtoc.dosRelease).AppendLine();
sb.AppendFormat(Localization.Disk_volume_number_0, _vtoc.volumeNumber).AppendLine();
sb.AppendFormat(Localization.Sectors_allocated_at_most_in_track_0, _vtoc.lastAllocatedSector).AppendLine();
sb.AppendFormat(Localization._0_tracks_in_volume, _vtoc.tracks).AppendLine();
sb.AppendFormat(Localization._0_sectors_per_track, _vtoc.sectorsPerTrack).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_sector, _vtoc.bytesPerSector).AppendLine();
sb.AppendFormat(Localization.Disk_volume_number_0, _vtoc.volumeNumber).AppendLine();
sb.AppendFormat(Localization.Sectors_allocated_at_most_in_track_0, _vtoc.lastAllocatedSector).AppendLine();
sb.AppendFormat(Localization._0_tracks_in_volume, _vtoc.tracks).AppendLine();
sb.AppendFormat(Localization._0_sectors_per_track, _vtoc.sectorsPerTrack).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_sector, _vtoc.bytesPerSector).AppendLine();
sb.AppendLine(_vtoc.allocationDirection > 0 ? Localization.Track_allocation_is_forward
sb.AppendLine(_vtoc.allocationDirection > 0
? Localization.Track_allocation_is_forward
: Localization.Track_allocation_is_reverse);
information = sb.ToString();
@@ -104,4 +107,6 @@ public sealed partial class AppleDOS
Type = FS_TYPE
};
}
#endregion
}

View File

@@ -33,6 +33,108 @@ namespace Aaru.Filesystems;
public sealed partial class AppleDOS
{
#region Nested type: AppleDosDirNode
sealed class AppleDosDirNode : IDirNode
{
internal string[] _contents;
internal int _position;
#region IDirNode Members
/// <inheritdoc />
public string Path { get; init; }
#endregion
}
#endregion
#region Nested type: AppleDosFileNode
sealed class AppleDosFileNode : IFileNode
{
internal byte[] _cache;
#region IFileNode Members
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; set; }
#endregion
}
#endregion
#region Nested type: CatalogSector
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CatalogSector
{
public readonly byte unused1;
public readonly byte trackOfNext;
public readonly byte sectorOfNext;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly byte[] unused2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public readonly FileEntry[] entries;
}
#endregion
#region Nested type: FileEntry
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct FileEntry
{
public readonly byte extentTrack;
public readonly byte extentSector;
public readonly byte typeAndFlags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public readonly byte[] filename;
public readonly ushort length;
}
#endregion
#region Nested type: TrackSectorList
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct TrackSectorList
{
public readonly byte unused1;
public readonly byte nextListTrack;
public readonly byte nextListSector;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public readonly byte[] unused2;
public readonly ushort sectorOffset;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public readonly byte[] unused3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 122)]
public readonly TrackSectorListEntry[] entries;
}
#endregion
#region Nested type: TrackSectorListEntry
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct TrackSectorListEntry
{
public readonly byte track;
public readonly byte sector;
}
#endregion
#region Nested type: Vtoc
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct Vtoc
{
@@ -59,67 +161,5 @@ public sealed partial class AppleDOS
public readonly byte[] bitmap;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CatalogSector
{
public readonly byte unused1;
public readonly byte trackOfNext;
public readonly byte sectorOfNext;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly byte[] unused2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public readonly FileEntry[] entries;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct FileEntry
{
public readonly byte extentTrack;
public readonly byte extentSector;
public readonly byte typeAndFlags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public readonly byte[] filename;
public readonly ushort length;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct TrackSectorList
{
public readonly byte unused1;
public readonly byte nextListTrack;
public readonly byte nextListSector;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public readonly byte[] unused2;
public readonly ushort sectorOffset;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public readonly byte[] unused3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 122)]
public readonly TrackSectorListEntry[] entries;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct TrackSectorListEntry
{
public readonly byte track;
public readonly byte sector;
}
sealed class AppleDosFileNode : IFileNode
{
internal byte[] _cache;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; set; }
}
sealed class AppleDosDirNode : IDirNode
{
internal string[] _contents;
internal int _position;
/// <inheritdoc />
public string Path { get; init; }
}
#endregion
}

View File

@@ -41,9 +41,11 @@ namespace Aaru.Filesystems;
public sealed partial class AppleDOS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
{
_device = imagePlugin;
_start = partition.Start;
@@ -156,4 +158,6 @@ public sealed partial class AppleDOS
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -38,6 +38,8 @@ namespace Aaru.Filesystems;
public sealed partial class AppleDOS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber ListXAttr(string path, out List<string> xattrs)
{
@@ -46,10 +48,7 @@ public sealed partial class AppleDOS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -61,7 +60,7 @@ public sealed partial class AppleDOS
xattrs = new List<string>();
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) {}
else
@@ -84,10 +83,7 @@ public sealed partial class AppleDOS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -97,7 +93,7 @@ public sealed partial class AppleDOS
if(filename.Length > 30)
return ErrorNumber.NameTooLong;
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
if(_debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0))
return ErrorNumber.NoSuchExtendedAttribute;
@@ -128,4 +124,6 @@ public sealed partial class AppleDOS
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -42,10 +42,16 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the Apple Hierarchical File System (HFS)</summary>
public sealed partial class AppleHFS : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.Name_Apple_Hierarchical_File_System;
/// <inheritdoc />
public Guid Id => new("36405F8D-0D26-6ECC-0BBB-1D5225FF404F");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -34,17 +34,7 @@ namespace Aaru.Filesystems;
public sealed partial class AppleHFS
{
enum NodeType : sbyte
{
/// <summary>Index node</summary>
ndIndxNode = 0,
/// <summary>Header node</summary>
ndHdrNode = 1,
/// <summary>Map node</summary>
ndMapNode = 2,
/// <summary>Leaf node</summary>
ndLeafNode = -1
}
#region Nested type: CatDataType
enum CatDataType : sbyte
{
@@ -58,8 +48,31 @@ public sealed partial class AppleHFS
cdrFThdRec = 4
}
#endregion
#region Nested type: ForkType
enum ForkType : sbyte
{
Data = 0, Resource = -1
Data = 0,
Resource = -1
}
#endregion
#region Nested type: NodeType
enum NodeType : sbyte
{
/// <summary>Index node</summary>
ndIndxNode = 0,
/// <summary>Header node</summary>
ndHdrNode = 1,
/// <summary>Map node</summary>
ndMapNode = 2,
/// <summary>Leaf node</summary>
ndLeafNode = -1
}
#endregion
}

View File

@@ -41,6 +41,8 @@ namespace Aaru.Filesystems;
// https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf
public sealed partial class AppleHFS
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -58,10 +60,8 @@ public sealed partial class AppleHFS
if(errno != ErrorNumber.NoError)
return false;
foreach(int offset in new[]
{
0, 0x200, 0x400, 0x600, 0x800, 0xA00
}.Where(offset => mdbSector.Length >= offset + 0x7C + 2))
foreach(int offset in new[] { 0, 0x200, 0x400, 0x600, 0x800, 0xA00 }.Where(
offset => mdbSector.Length >= offset + 0x7C + 2))
{
drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, offset);
@@ -111,7 +111,7 @@ public sealed partial class AppleHFS
ushort drSigWord;
ErrorNumber errno;
bool apmFromHddOnCd = false;
var apmFromHddOnCd = false;
if(imagePlugin.Info.SectorSize is 2352 or 2448 or 2048)
{
@@ -120,10 +120,7 @@ public sealed partial class AppleHFS
if(errno != ErrorNumber.NoError)
return;
foreach(int offset in new[]
{
0, 0x200, 0x400, 0x600, 0x800, 0xA00
})
foreach(int offset in new[] { 0, 0x200, 0x400, 0x600, 0x800, 0xA00 })
{
drSigWord = BigEndianBitConverter.ToUInt16(tmpSector, offset);
@@ -174,7 +171,7 @@ public sealed partial class AppleHFS
sb.AppendLine(Localization.HFS_uses_512_bytes_sector_while_device_uses_2048_bytes_sector).AppendLine();
sb.AppendLine(Localization.Master_Directory_Block);
sb.AppendFormat(Localization.Creation_date_0, DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
sb.AppendFormat(Localization.Creation_date_0, DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
sb.AppendFormat(Localization.Last_modification_date_0, DateHandlers.MacToDateTime(mdb.drLsMod)).AppendLine();
if(mdb.drVolBkUp > 0)
@@ -188,7 +185,8 @@ public sealed partial class AppleHFS
if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.HardwareLock))
sb.AppendLine(Localization.Volume_is_locked_by_hardware);
sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) ? Localization.Volume_was_unmonted
sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted)
? Localization.Volume_was_unmonted
: Localization.Volume_is_mounted);
if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SparedBadBlocks))
@@ -212,22 +210,22 @@ public sealed partial class AppleHFS
if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SoftwareLock))
sb.AppendLine(Localization.Volume_is_locked_by_software);
sb.AppendFormat(Localization._0_files_in_root_directory, mdb.drNmFls).AppendLine();
sb.AppendFormat(Localization._0_files_in_root_directory, mdb.drNmFls).AppendLine();
sb.AppendFormat(Localization._0_directories_in_root_directory, mdb.drNmRtDirs).AppendLine();
sb.AppendFormat(Localization._0_files_in_volume, mdb.drFilCnt).AppendLine();
sb.AppendFormat(Localization._0_directories_in_volume, mdb.drDirCnt).AppendLine();
sb.AppendFormat(Localization.Volume_write_count_0, mdb.drWrCnt).AppendLine();
sb.AppendFormat(Localization._0_files_in_volume, mdb.drFilCnt).AppendLine();
sb.AppendFormat(Localization._0_directories_in_volume, mdb.drDirCnt).AppendLine();
sb.AppendFormat(Localization.Volume_write_count_0, mdb.drWrCnt).AppendLine();
sb.AppendFormat(Localization.Volume_bitmap_starting_sector_in_512_bytes_0, mdb.drVBMSt).AppendLine();
sb.AppendFormat(Localization.Next_allocation_block_0, mdb.drAllocPtr).AppendLine();
sb.AppendFormat(Localization._0_volume_allocation_blocks, mdb.drNmAlBlks).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_allocation_block, mdb.drAlBlkSiz).AppendLine();
sb.AppendFormat(Localization._0_bytes_to_allocate_when_extending_a_file, mdb.drClpSiz).AppendLine();
sb.AppendFormat(Localization.Volume_bitmap_starting_sector_in_512_bytes_0, mdb.drVBMSt).AppendLine();
sb.AppendFormat(Localization.Next_allocation_block_0, mdb.drAllocPtr).AppendLine();
sb.AppendFormat(Localization._0_volume_allocation_blocks, mdb.drNmAlBlks).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_allocation_block, mdb.drAlBlkSiz).AppendLine();
sb.AppendFormat(Localization._0_bytes_to_allocate_when_extending_a_file, mdb.drClpSiz).AppendLine();
sb.AppendFormat(Localization._0_bytes_to_allocate_when_extending_a_Extents_B_Tree, mdb.drXTClpSiz).AppendLine();
sb.AppendFormat(Localization._0_bytes_to_allocate_when_extending_a_Catalog_B_Tree, mdb.drCTClpSiz).AppendLine();
sb.AppendFormat(Localization.Sector_of_first_allocation_block_0, mdb.drAlBlSt).AppendLine();
sb.AppendFormat(Localization.Next_unused_CNID_0, mdb.drNxtCNID).AppendLine();
sb.AppendFormat(Localization._0_unused_allocation_blocks, mdb.drFreeBks).AppendLine();
sb.AppendFormat(Localization.Sector_of_first_allocation_block_0, mdb.drAlBlSt).AppendLine();
sb.AppendFormat(Localization.Next_unused_CNID_0, mdb.drNxtCNID).AppendLine();
sb.AppendFormat(Localization._0_unused_allocation_blocks, mdb.drFreeBks).AppendLine();
sb.AppendFormat(Localization._0_bytes_in_the_Extents_B_Tree, mdb.drXTFlSize).AppendLine();
sb.AppendFormat(Localization._0_bytes_in_the_Catalog_B_Tree, mdb.drCTFlSize).AppendLine();
@@ -235,11 +233,11 @@ public sealed partial class AppleHFS
sb.AppendFormat(Localization.Volume_name_0, StringHandlers.PascalToString(mdb.drVN, encoding)).AppendLine();
sb.AppendLine(Localization.Finder_info);
sb.AppendFormat(Localization.CNID_of_bootable_system_directory_0, mdb.drFndrInfo0).AppendLine();
sb.AppendFormat(Localization.CNID_of_first_run_application_directory_0, mdb.drFndrInfo1).AppendLine();
sb.AppendFormat(Localization.CNID_of_previously_opened_directory_0, mdb.drFndrInfo2).AppendLine();
sb.AppendFormat(Localization.CNID_of_bootable_system_directory_0, mdb.drFndrInfo0).AppendLine();
sb.AppendFormat(Localization.CNID_of_first_run_application_directory_0, mdb.drFndrInfo1).AppendLine();
sb.AppendFormat(Localization.CNID_of_previously_opened_directory_0, mdb.drFndrInfo2).AppendLine();
sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_8_or_9_directory_0, mdb.drFndrInfo3).AppendLine();
sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_X_directory_0, mdb.drFndrInfo5).AppendLine();
sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_X_directory_0, mdb.drFndrInfo5).AppendLine();
if(mdb.drFndrInfo6 != 0 &&
mdb.drFndrInfo7 != 0)
@@ -248,12 +246,12 @@ public sealed partial class AppleHFS
if(mdb.drEmbedSigWord == AppleCommon.HFSP_MAGIC)
{
sb.AppendLine(Localization.Volume_wraps_a_HFS_Plus_volume);
sb.AppendFormat(Localization.Starting_block_of_the_HFS_Plus_volume_0, mdb.xdrStABNt).AppendLine();
sb.AppendFormat(Localization.Starting_block_of_the_HFS_Plus_volume_0, mdb.xdrStABNt).AppendLine();
sb.AppendFormat(Localization.Allocations_blocks_of_the_HFS_Plus_volume_0, mdb.xdrNumABlks).AppendLine();
}
else
{
sb.AppendFormat(Localization._0_blocks_in_volume_cache, mdb.drVCSize).AppendLine();
sb.AppendFormat(Localization._0_blocks_in_volume_cache, mdb.drVCSize).AppendLine();
sb.AppendFormat(Localization._0_blocks_in_volume_bitmap_cache, mdb.drVBMCSize).AppendLine();
sb.AppendFormat(Localization._0_blocks_in_volume_common_cache, mdb.drCtlCSize).AppendLine();
}
@@ -278,9 +276,7 @@ public sealed partial class AppleHFS
metadata = new FileSystem();
if(mdb.drVolBkUp > 0)
{
metadata.BackupDate = DateHandlers.MacToDateTime(mdb.drVolBkUp);
}
metadata.Bootable = bootBlockInfo != null || mdb.drFndrInfo0 != 0 || mdb.drFndrInfo3 != 0 ||
mdb.drFndrInfo5 != 0;
@@ -289,18 +285,14 @@ public sealed partial class AppleHFS
metadata.ClusterSize = mdb.drAlBlkSiz;
if(mdb.drCrDate > 0)
{
metadata.CreationDate = DateHandlers.MacToDateTime(mdb.drCrDate);
}
metadata.Dirty = !mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted);
metadata.Files = mdb.drFilCnt;
metadata.FreeClusters = mdb.drFreeBks;
if(mdb.drLsMod > 0)
{
metadata.ModificationDate = DateHandlers.MacToDateTime(mdb.drLsMod);
}
metadata.Type = FS_TYPE;
metadata.VolumeName = StringHandlers.PascalToString(mdb.drVN, encoding);
@@ -309,4 +301,6 @@ public sealed partial class AppleHFS
mdb.drFndrInfo7 != 0)
metadata.VolumeSerial = $"{mdb.drFndrInfo6:X8}{mdb.drFndrInfo7:X8}";
}
#endregion
}

View File

@@ -39,6 +39,229 @@ namespace Aaru.Filesystems;
// https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf
public sealed partial class AppleHFS
{
#region Nested type: BTHdrRed
/// <summary>B*-tree header</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct BTHdrRed
{
/// <summary>Current depth of tree.</summary>
public readonly ushort bthDepth;
/// <summary>Number of root node.</summary>
public readonly uint bthRoot;
/// <summary>Number of leaf records in tree.</summary>
public readonly uint bthNRecs;
/// <summary>Number of first leaf node.</summary>
public readonly uint bthFNode;
/// <summary>Number of last leaf node.</summary>
public readonly uint bthLNode;
/// <summary>Size of a node.</summary>
public readonly ushort bthNodeSize;
/// <summary>Maximum length of a key.</summary>
public readonly ushort bthKeyLen;
/// <summary>Total number of nodes in tree.</summary>
public readonly uint bthNNodes;
/// <summary>Number of free nodes.</summary>
public readonly uint bthFree;
/// <summary>Reserved</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)]
public readonly sbyte[] bthResv;
}
#endregion
#region Nested type: CatDataRec
/// <summary>Catalog data record header</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CatDataRec
{
public readonly CatDataType cdrType;
public readonly sbyte cdrResvr2;
}
#endregion
#region Nested type: CatKeyRec
/// <summary>Catalog key record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CatKeyRec
{
/// <summary>Key length.</summary>
public readonly sbyte ckrKeyLen;
/// <summary>Reserved.</summary>
public readonly sbyte ckrResrv1;
/// <summary>Parent directory ID.</summary>
public readonly uint ckrParID;
/// <summary>Catalog node name. Full 32 bytes in index nodes but only the needed bytes, padded to word, in leaf nodes.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public readonly byte[] ckrCName;
}
#endregion
#region Nested type: CdrDirRec
/// <summary>Directory record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CdrDirRec
{
public readonly CatDataRec dirHdr;
/// <summary>Directory flags.</summary>
public readonly ushort dirFlags;
/// <summary>Directory valence.</summary>
public readonly ushort dirVal;
/// <summary>Directory ID.</summary>
public readonly uint dirDirID;
/// <summary>Date and time of creation.</summary>
public readonly uint dirCrDat;
/// <summary>Date and time of last modification.</summary>
public readonly uint dirMdDat;
/// <summary>Date and time of last backup.</summary>
public readonly uint dirBkDat;
/// <summary>Finder information.</summary>
public readonly AppleCommon.DInfo dirUsrInfo;
/// <summary>Additional Finder information.</summary>
public readonly AppleCommon.DXInfo dirFndrInfo;
/// <summary>Reserved</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly uint[] dirResrv;
}
#endregion
#region Nested type: CdrFilRec
/// <summary>File record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CdrFilRec
{
public readonly CatDataRec filHdr;
/// <summary>File flags.</summary>
public readonly sbyte filFlags;
/// <summary>File type.</summary>
public readonly sbyte filType;
/// <summary>Finder information.</summary>
public readonly AppleCommon.FInfo filUsrWds;
/// <summary>File ID.</summary>
public readonly uint filFlNum;
/// <summary>First allocation block of data fork.</summary>
public readonly ushort filStBlk;
/// <summary>Logical EOF of data fork.</summary>
public readonly uint filLgLen;
/// <summary>Physical EOF of data fork.</summary>
public readonly uint filPyLen;
/// <summary>First allocation block of resource fork.</summary>
public readonly ushort filRStBlk;
/// <summary>Logical EOF of resource fork.</summary>
public readonly uint filRLgLen;
/// <summary>Physical EOF of resource fork.</summary>
public readonly uint filRPyLen;
/// <summary>Date and time of creation.</summary>
public readonly uint filCrDat;
/// <summary>Date and time of last modification.</summary>
public readonly uint filMdDat;
/// <summary>Date and time of last backup.</summary>
public readonly uint filBkDat;
/// <summary>Additional Finder information.</summary>
public readonly AppleCommon.FXInfo filFndrInfo;
/// <summary>File clump size.</summary>
public readonly ushort filClpSize;
/// <summary>First data fork extent record.</summary>
public readonly ExtDataRec filExtRec;
/// <summary>First resource fork extent record.</summary>
public readonly ExtDataRec filRExtRec;
/// <summary>Reserved</summary>
public readonly uint filResrv;
}
#endregion
#region Nested type: CdrFThdRec
/// <summary>File thread record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CdrFThdRec
{
public readonly CatDataRec fthdHdr;
/// <summary>Reserved.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public readonly uint[] fthdResrv;
/// <summary>Parent ID for this file.</summary>
public readonly uint fthdParID;
/// <summary>Name of this file.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public readonly byte[] fthdCName;
}
#endregion
#region Nested type: CdrThdRec
/// <summary>Directory thread record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CdrThdRec
{
public readonly CatDataRec thdHdr;
/// <summary>Reserved.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public readonly uint[] thdResrv;
/// <summary>Parent ID for this directory.</summary>
public readonly uint thdParID;
/// <summary>Name of this directory.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public readonly byte[] thdCName;
}
#endregion
#region Nested type: ExtDataRec
/// <summary>Extent data record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct ExtDataRec
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly ExtDescriptor[] xdr;
}
#endregion
#region Nested type: ExtDescriptor
/// <summary>Extent descriptor</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct ExtDescriptor
{
/// <summary>First allocation block</summary>
public readonly ushort xdrStABN;
/// <summary>Number of allocation blocks</summary>
public readonly ushort xdrNumABlks;
}
#endregion
#region Nested type: ExtKeyRec
/// <summary>Extent key record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct ExtKeyRec
{
/// <summary>Key length.</summary>
public readonly sbyte xkrKeyLen;
/// <summary>Fork type.</summary>
public readonly ForkType xkrFkType;
/// <summary>File number.</summary>
public readonly uint xkrFNum;
/// <summary>Starting file allocation block.</summary>
public readonly ushort xkrFABN;
}
#endregion
#region Nested type: MasterDirectoryBlock
/// <summary>Master Directory Block, should be sector 2 in volume</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct MasterDirectoryBlock // Should be sector 2 in volume
@@ -128,6 +351,10 @@ public sealed partial class AppleHFS
public readonly uint drCTFlSize;
}
#endregion
#region Nested type: NodeDescriptor
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct NodeDescriptor
{
@@ -145,184 +372,5 @@ public sealed partial class AppleHFS
public readonly ushort ndResv2;
}
/// <summary>B*-tree header</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct BTHdrRed
{
/// <summary>Current depth of tree.</summary>
public readonly ushort bthDepth;
/// <summary>Number of root node.</summary>
public readonly uint bthRoot;
/// <summary>Number of leaf records in tree.</summary>
public readonly uint bthNRecs;
/// <summary>Number of first leaf node.</summary>
public readonly uint bthFNode;
/// <summary>Number of last leaf node.</summary>
public readonly uint bthLNode;
/// <summary>Size of a node.</summary>
public readonly ushort bthNodeSize;
/// <summary>Maximum length of a key.</summary>
public readonly ushort bthKeyLen;
/// <summary>Total number of nodes in tree.</summary>
public readonly uint bthNNodes;
/// <summary>Number of free nodes.</summary>
public readonly uint bthFree;
/// <summary>Reserved</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)]
public readonly sbyte[] bthResv;
}
/// <summary>Catalog key record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CatKeyRec
{
/// <summary>Key length.</summary>
public readonly sbyte ckrKeyLen;
/// <summary>Reserved.</summary>
public readonly sbyte ckrResrv1;
/// <summary>Parent directory ID.</summary>
public readonly uint ckrParID;
/// <summary>Catalog node name. Full 32 bytes in index nodes but only the needed bytes, padded to word, in leaf nodes.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public readonly byte[] ckrCName;
}
/// <summary>Catalog data record header</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CatDataRec
{
public readonly CatDataType cdrType;
public readonly sbyte cdrResvr2;
}
/// <summary>Directory record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CdrDirRec
{
public readonly CatDataRec dirHdr;
/// <summary>Directory flags.</summary>
public readonly ushort dirFlags;
/// <summary>Directory valence.</summary>
public readonly ushort dirVal;
/// <summary>Directory ID.</summary>
public readonly uint dirDirID;
/// <summary>Date and time of creation.</summary>
public readonly uint dirCrDat;
/// <summary>Date and time of last modification.</summary>
public readonly uint dirMdDat;
/// <summary>Date and time of last backup.</summary>
public readonly uint dirBkDat;
/// <summary>Finder information.</summary>
public readonly AppleCommon.DInfo dirUsrInfo;
/// <summary>Additional Finder information.</summary>
public readonly AppleCommon.DXInfo dirFndrInfo;
/// <summary>Reserved</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly uint[] dirResrv;
}
/// <summary>File record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CdrFilRec
{
public readonly CatDataRec filHdr;
/// <summary>File flags.</summary>
public readonly sbyte filFlags;
/// <summary>File type.</summary>
public readonly sbyte filType;
/// <summary>Finder information.</summary>
public readonly AppleCommon.FInfo filUsrWds;
/// <summary>File ID.</summary>
public readonly uint filFlNum;
/// <summary>First allocation block of data fork.</summary>
public readonly ushort filStBlk;
/// <summary>Logical EOF of data fork.</summary>
public readonly uint filLgLen;
/// <summary>Physical EOF of data fork.</summary>
public readonly uint filPyLen;
/// <summary>First allocation block of resource fork.</summary>
public readonly ushort filRStBlk;
/// <summary>Logical EOF of resource fork.</summary>
public readonly uint filRLgLen;
/// <summary>Physical EOF of resource fork.</summary>
public readonly uint filRPyLen;
/// <summary>Date and time of creation.</summary>
public readonly uint filCrDat;
/// <summary>Date and time of last modification.</summary>
public readonly uint filMdDat;
/// <summary>Date and time of last backup.</summary>
public readonly uint filBkDat;
/// <summary>Additional Finder information.</summary>
public readonly AppleCommon.FXInfo filFndrInfo;
/// <summary>File clump size.</summary>
public readonly ushort filClpSize;
/// <summary>First data fork extent record.</summary>
public readonly ExtDataRec filExtRec;
/// <summary>First resource fork extent record.</summary>
public readonly ExtDataRec filRExtRec;
/// <summary>Reserved</summary>
public readonly uint filResrv;
}
/// <summary>Directory thread record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CdrThdRec
{
public readonly CatDataRec thdHdr;
/// <summary>Reserved.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public readonly uint[] thdResrv;
/// <summary>Parent ID for this directory.</summary>
public readonly uint thdParID;
/// <summary>Name of this directory.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public readonly byte[] thdCName;
}
/// <summary>File thread record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct CdrFThdRec
{
public readonly CatDataRec fthdHdr;
/// <summary>Reserved.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public readonly uint[] fthdResrv;
/// <summary>Parent ID for this file.</summary>
public readonly uint fthdParID;
/// <summary>Name of this file.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public readonly byte[] fthdCName;
}
/// <summary>Extent descriptor</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct ExtDescriptor
{
/// <summary>First allocation block</summary>
public readonly ushort xdrStABN;
/// <summary>Number of allocation blocks</summary>
public readonly ushort xdrNumABlks;
}
/// <summary>Extent data record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct ExtDataRec
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly ExtDescriptor[] xdr;
}
/// <summary>Extent key record</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct ExtKeyRec
{
/// <summary>Key length.</summary>
public readonly sbyte xkrKeyLen;
/// <summary>Fork type.</summary>
public readonly ForkType xkrFkType;
/// <summary>File number.</summary>
public readonly uint xkrFNum;
/// <summary>Starting file allocation block.</summary>
public readonly ushort xkrFABN;
}
#endregion
}

View File

@@ -36,10 +36,16 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Apple Hierarchical File System Plus (HFS+)</summary>
public sealed partial class AppleHFSPlus : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.AppleHFSPlus_Name;
/// <inheritdoc />
public Guid Id => new("36405F8D-0D26-6EBE-436F-62F0586B4F08");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -41,6 +41,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Apple Hierarchical File System Plus (HFS+)</summary>
public sealed partial class AppleHFSPlus
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -62,7 +64,7 @@ public sealed partial class AppleHFSPlus
if(vhSector.Length < 0x800)
return false;
ushort drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400);
var drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400);
if(drSigWord == AppleCommon.HFS_MAGIC) // "BD"
{
@@ -71,13 +73,13 @@ public sealed partial class AppleHFSPlus
if(drSigWord == AppleCommon.HFSP_MAGIC) // "H+"
{
// ReSharper disable once InconsistentNaming
ushort xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E);
var xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E);
uint drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414);
var drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414);
ushort drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);
var drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);
hfspOffset = (ulong)(((drAlBlSt * 512) + (xdrStABNt * drAlBlkSiz)) / imagePlugin.Info.SectorSize);
hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize);
}
else
hfspOffset = 0;
@@ -118,7 +120,7 @@ public sealed partial class AppleHFSPlus
if(errno != ErrorNumber.NoError)
return;
ushort drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400);
var drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400);
if(drSigWord == AppleCommon.HFS_MAGIC) // "BD"
{
@@ -127,13 +129,13 @@ public sealed partial class AppleHFSPlus
if(drSigWord == AppleCommon.HFSP_MAGIC) // "H+"
{
// ReSharper disable once InconsistentNaming
ushort xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E);
var xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E);
uint drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414);
var drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414);
ushort drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);
var drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);
hfspOffset = (ulong)(((drAlBlSt * 512) + (xdrStABNt * drAlBlkSiz)) / imagePlugin.Info.SectorSize);
hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize);
wrapped = true;
}
else
@@ -177,7 +179,7 @@ public sealed partial class AppleHFSPlus
if(wrapped)
sb.AppendLine(Localization.Volume_is_wrapped_inside_an_HFS_volume);
byte[] tmp = new byte[0x400];
var tmp = new byte[0x400];
Array.Copy(vhSector, 0x400, tmp, 0, 0x400);
vhSector = tmp;
@@ -223,14 +225,18 @@ public sealed partial class AppleHFSPlus
AppendLine();
if(vh.backupDate > 0)
{
sb.AppendFormat(Localization.Last_backup_date_0, DateHandlers.MacToDateTime(vh.backupDate)).
AppendLine();
}
else
sb.AppendLine(Localization.Volume_has_never_been_backed_up);
if(vh.backupDate > 0)
{
sb.AppendFormat(Localization.Last_check_date_0, DateHandlers.MacToDateTime(vh.checkedDate)).
AppendLine();
}
else
sb.AppendLine(Localization.Volume_has_never_been_checked_up);
@@ -250,11 +256,11 @@ public sealed partial class AppleHFSPlus
sb.AppendFormat(Localization.Attributes_File_is_0_bytes, vh.attributesFile_logicalSize).AppendLine();
sb.AppendFormat(Localization.Startup_File_is_0_bytes, vh.startupFile_logicalSize).AppendLine();
sb.AppendLine(Localization.Finder_info);
sb.AppendFormat(Localization.CNID_of_bootable_system_directory_0, vh.drFndrInfo0).AppendLine();
sb.AppendFormat(Localization.CNID_of_first_run_application_directory_0, vh.drFndrInfo1).AppendLine();
sb.AppendFormat(Localization.CNID_of_previously_opened_directory_0, vh.drFndrInfo2).AppendLine();
sb.AppendFormat(Localization.CNID_of_bootable_system_directory_0, vh.drFndrInfo0).AppendLine();
sb.AppendFormat(Localization.CNID_of_first_run_application_directory_0, vh.drFndrInfo1).AppendLine();
sb.AppendFormat(Localization.CNID_of_previously_opened_directory_0, vh.drFndrInfo2).AppendLine();
sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_8_or_9_directory_0, vh.drFndrInfo3).AppendLine();
sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_X_directory_0, vh.drFndrInfo5).AppendLine();
sb.AppendFormat(Localization.CNID_of_bootable_Mac_OS_X_directory_0, vh.drFndrInfo5).AppendLine();
if(vh.drFndrInfo6 != 0 &&
vh.drFndrInfo7 != 0)
@@ -263,34 +269,28 @@ public sealed partial class AppleHFSPlus
metadata = new FileSystem();
if(vh.backupDate > 0)
{
metadata.BackupDate = DateHandlers.MacToDateTime(vh.backupDate);
}
metadata.Bootable |= vh.drFndrInfo0 != 0 || vh.drFndrInfo3 != 0 || vh.drFndrInfo5 != 0;
metadata.Clusters = vh.totalBlocks;
metadata.ClusterSize = vh.blockSize;
if(vh.createDate > 0)
{
metadata.CreationDate = DateHandlers.MacToDateTime(vh.createDate);
}
metadata.Dirty = (vh.attributes & 0x100) != 0x100;
metadata.Files = vh.fileCount;
metadata.FreeClusters = vh.freeBlocks;
if(vh.modifyDate > 0)
{
metadata.ModificationDate = DateHandlers.MacToDateTime(vh.modifyDate);
}
metadata.Type = vh.signature switch
{
0x482B => FS_TYPE_HFSP,
0x4858 => FS_TYPE_HFSX,
_ => metadata.Type
};
{
0x482B => FS_TYPE_HFSP,
0x4858 => FS_TYPE_HFSX,
_ => metadata.Type
};
if(vh.drFndrInfo6 != 0 &&
vh.drFndrInfo7 != 0)
@@ -306,4 +306,6 @@ public sealed partial class AppleHFSPlus
information = sb.ToString();
}
#endregion
}

View File

@@ -35,6 +35,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of Apple Hierarchical File System Plus (HFS+)</summary>
public sealed partial class AppleHFSPlus
{
#region Nested type: VolumeHeader
/// <summary>HFS+ Volume Header, should be at offset 0x0400 bytes in volume with a size of 532 bytes</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct VolumeHeader
@@ -300,4 +302,6 @@ public sealed partial class AppleHFSPlus
/// <summary>0x200</summary>
public readonly uint startupFile_extents_blockCount7;
}
#endregion
}

View File

@@ -40,32 +40,37 @@ namespace Aaru.Filesystems;
public sealed partial class AppleMFS : IReadOnlyFilesystem
{
const string MODULE_NAME = "Apple MFS plugin";
bool _mounted;
byte[] _bitmapTags;
uint[] _blockMap;
byte[] _blockMapBytes;
byte[] _bootBlocks;
byte[] _bootTags;
bool _debug;
IMediaImage _device;
ulong _partitionStart;
Dictionary<uint, string> _idToFilename;
Dictionary<uint, FileEntry> _idToEntry;
Dictionary<string, uint> _filenameToId;
MasterDirectoryBlock _volMdb;
byte[] _bootBlocks;
byte[] _mdbBlocks;
byte[] _directoryBlocks;
byte[] _blockMapBytes;
uint[] _blockMap;
int _sectorsPerBlock;
byte[] _bootTags;
byte[] _mdbTags;
byte[] _directoryTags;
byte[] _bitmapTags;
Encoding _encoding;
Dictionary<string, uint> _filenameToId;
Dictionary<uint, FileEntry> _idToEntry;
Dictionary<uint, string> _idToFilename;
byte[] _mdbBlocks;
byte[] _mdbTags;
bool _mounted;
ulong _partitionStart;
int _sectorsPerBlock;
MasterDirectoryBlock _volMdb;
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public string Name => Localization.AppleMFS_Name;
/// <inheritdoc />
public FileSystem Metadata { get; private set; }
/// <inheritdoc />
public Guid Id => new("36405F8D-0D26-4066-6538-5DBF5D065C3A");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
@@ -77,10 +82,10 @@ public sealed partial class AppleMFS : IReadOnlyFilesystem
/// <inheritdoc />
public Dictionary<string, string> Namespaces => null;
#endregion
static Dictionary<string, string> GetDefaultOptions() => new()
{
{
"debug", false.ToString()
}
{ "debug", false.ToString() }
};
}

View File

@@ -39,6 +39,8 @@ namespace Aaru.Filesystems;
// Information from Inside Macintosh Volume II
public sealed partial class AppleMFS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber OpenDir(string path, out IDirNode node)
{
@@ -51,7 +53,7 @@ public sealed partial class AppleMFS
string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0)
return ErrorNumber.NotSupported;
List<string> contents = _idToFilename.Select(kvp => kvp.Value).ToList();
var contents = _idToFilename.Select(kvp => kvp.Value).ToList();
if(_debug)
{
@@ -109,13 +111,15 @@ public sealed partial class AppleMFS
return ErrorNumber.NoError;
}
#endregion
bool FillDirectory()
{
_idToFilename = new Dictionary<uint, string>();
_idToEntry = new Dictionary<uint, FileEntry>();
_filenameToId = new Dictionary<string, uint>();
int offset = 0;
var offset = 0;
while(offset + 51 < _directoryBlocks.Length)
{
@@ -159,12 +163,12 @@ public sealed partial class AppleMFS
_filenameToId.Add(lowerFilename, entry.flFlNum);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flFlags = {0}", entry.flFlags);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flTyp = {0}", entry.flTyp);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flFlNum = {0}", entry.flFlNum);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flStBlk = {0}", entry.flStBlk);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flLgLen = {0}", entry.flLgLen);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flPyLen = {0}", entry.flPyLen);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flFlags = {0}", entry.flFlags);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flTyp = {0}", entry.flTyp);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flFlNum = {0}", entry.flFlNum);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flStBlk = {0}", entry.flStBlk);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flLgLen = {0}", entry.flLgLen);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flPyLen = {0}", entry.flPyLen);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flRStBlk = {0}", entry.flRStBlk);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flRLgLen = {0}", entry.flRLgLen);
AaruConsole.DebugWriteLine(MODULE_NAME, "entry.flRPyLen = {0}", entry.flRPyLen);

View File

@@ -40,6 +40,8 @@ namespace Aaru.Filesystems;
// Information from Inside Macintosh Volume II
public sealed partial class AppleMFS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber GetAttributes(string path, out FileAttributes attributes)
{
@@ -48,10 +50,7 @@ public sealed partial class AppleMFS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -202,10 +201,7 @@ public sealed partial class AppleMFS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -213,10 +209,11 @@ public sealed partial class AppleMFS
path = pathElements[0];
if(_debug)
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
{
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
{
stat = new FileEntryInfo
{
@@ -228,26 +225,26 @@ public sealed partial class AppleMFS
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0)
{
stat.Blocks = (_directoryBlocks.Length / stat.BlockSize) +
(_directoryBlocks.Length % stat.BlockSize);
stat.Blocks = _directoryBlocks.Length / stat.BlockSize +
_directoryBlocks.Length % stat.BlockSize;
stat.Length = _directoryBlocks.Length;
}
else if(string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0)
{
stat.Blocks = (_blockMapBytes.Length / stat.BlockSize) + (_blockMapBytes.Length % stat.BlockSize);
stat.Blocks = _blockMapBytes.Length / stat.BlockSize + _blockMapBytes.Length % stat.BlockSize;
stat.Length = _blockMapBytes.Length;
}
else if(string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 &&
_bootBlocks != null)
{
stat.Blocks = (_bootBlocks.Length / stat.BlockSize) + (_bootBlocks.Length % stat.BlockSize);
stat.Blocks = _bootBlocks.Length / stat.BlockSize + _bootBlocks.Length % stat.BlockSize;
stat.Length = _bootBlocks.Length;
}
else if(string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
{
stat.Blocks = (_mdbBlocks.Length / stat.BlockSize) + (_mdbBlocks.Length % stat.BlockSize);
stat.Blocks = _mdbBlocks.Length / stat.BlockSize + _mdbBlocks.Length % stat.BlockSize;
stat.Length = _mdbBlocks.Length;
}
else
@@ -255,6 +252,7 @@ public sealed partial class AppleMFS
return ErrorNumber.NoError;
}
}
if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
return ErrorNumber.NoSuchFile;
@@ -290,6 +288,8 @@ public sealed partial class AppleMFS
return ErrorNumber.NotImplemented;
}
#endregion
ErrorNumber ReadFile(string path, out byte[] buf, bool resourceFork, bool tags)
{
buf = null;
@@ -297,10 +297,7 @@ public sealed partial class AppleMFS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -373,6 +370,7 @@ public sealed partial class AppleMFS
else
{
if(resourceFork)
{
if(ms.Length < entry.flRLgLen)
buf = ms.ToArray();
else
@@ -380,6 +378,7 @@ public sealed partial class AppleMFS
buf = new byte[entry.flRLgLen];
Array.Copy(ms.ToArray(), 0, buf, 0, buf.Length);
}
}
else
{
if(ms.Length < entry.flLgLen)

View File

@@ -41,6 +41,8 @@ namespace Aaru.Filesystems;
// Information from Inside Macintosh Volume II
public sealed partial class AppleMFS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -52,7 +54,7 @@ public sealed partial class AppleMFS
if(errno != ErrorNumber.NoError)
return false;
ushort drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000);
var drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000);
return drSigWord == MFS_MAGIC;
}
@@ -97,20 +99,21 @@ public sealed partial class AppleMFS
mdb.drNxtFNum = BigEndianBitConverter.ToUInt32(mdbSector, 0x01E);
mdb.drFreeBks = BigEndianBitConverter.ToUInt16(mdbSector, 0x022);
mdb.drVNSiz = mdbSector[0x024];
byte[] variableSize = new byte[mdb.drVNSiz + 1];
var variableSize = new byte[mdb.drVNSiz + 1];
Array.Copy(mdbSector, 0x024, variableSize, 0, mdb.drVNSiz + 1);
mdb.drVN = StringHandlers.PascalToString(variableSize, encoding);
sb.AppendLine(Localization.AppleMFS_Name);
sb.AppendLine();
sb.AppendLine(Localization.Master_Directory_Block);
sb.AppendFormat(Localization.Creation_date_0, DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
sb.AppendFormat(Localization.Creation_date_0, DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
sb.AppendFormat(Localization.Last_backup_date_0, DateHandlers.MacToDateTime(mdb.drLsBkUp)).AppendLine();
if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.HardwareLock))
sb.AppendLine(Localization.Volume_is_locked_by_hardware);
sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) ? Localization.Volume_was_unmonted
sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted)
? Localization.Volume_was_unmonted
: Localization.Volume_is_mounted);
if(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SparedBadBlocks))
@@ -158,22 +161,20 @@ public sealed partial class AppleMFS
metadata = new FileSystem();
if(mdb.drLsBkUp > 0)
{
metadata.BackupDate = DateHandlers.MacToDateTime(mdb.drLsBkUp);
}
metadata.Bootable = bootBlockInfo != null;
metadata.Clusters = mdb.drNmAlBlks;
metadata.ClusterSize = mdb.drAlBlkSiz;
if(mdb.drCrDate > 0)
{
metadata.CreationDate = DateHandlers.MacToDateTime(mdb.drCrDate);
}
metadata.Files = mdb.drNmFls;
metadata.FreeClusters = mdb.drFreeBks;
metadata.Type = FS_TYPE;
metadata.VolumeName = mdb.drVN;
}
#endregion
}

View File

@@ -35,9 +35,96 @@ using Aaru.CommonTypes.Interfaces;
namespace Aaru.Filesystems;
// Information from Inside Macintosh Volume II
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "NotAccessedField.Local")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
public sealed partial class AppleMFS
{
#region Nested type: AppleMfsDirNode
sealed class AppleMfsDirNode : IDirNode
{
internal string[] _contents;
internal int _position;
#region IDirNode Members
/// <inheritdoc />
public string Path { get; init; }
#endregion
}
#endregion
#region Nested type: AppleMfsFileNode
sealed class AppleMfsFileNode : IFileNode
{
internal byte[] _cache;
#region IFileNode Members
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; set; }
#endregion
}
#endregion
#region Nested type: FileEntry
struct FileEntry
{
/// <summary>0x00, Entry flags</summary>
public FileFlags flFlags;
/// <summary>0x01, Version number</summary>
public byte flTyp;
/// <summary>0x02, FinderInfo</summary>
public AppleCommon.FInfo flUsrWds;
/// <summary>0x12, file ID</summary>
public uint flFlNum;
/// <summary>0x16, first allocation block of data fork</summary>
public ushort flStBlk;
/// <summary>0x18, logical end-of-file of data fork</summary>
public uint flLgLen;
/// <summary>0x1C, physical end-of-file of data fork</summary>
public uint flPyLen;
/// <summary>0x20, first allocation block of resource fork</summary>
public ushort flRStBlk;
/// <summary>0x22, logical end-of-file of resource fork</summary>
public uint flRLgLen;
/// <summary>0x26, physical end-of-file of resource fork</summary>
public uint flRPyLen;
/// <summary>0x2A, date and time of creation</summary>
public uint flCrDat;
/// <summary>0x2E, date and time of last modification</summary>
public uint flMdDat;
/// <summary>0x32, file name prefixed with length</summary>
public byte[] flNam;
}
#endregion
#region Nested type: FileFlags
[Flags]
enum FileFlags : byte
{
Locked = 0x01,
Used = 0x80
}
#endregion
#region Nested type: MasterDirectoryBlock
/// <summary>Master Directory Block, should be at offset 0x0400 bytes in volume</summary>
struct MasterDirectoryBlock
{
@@ -73,58 +160,5 @@ public sealed partial class AppleMFS
public string drVN;
}
[Flags]
enum FileFlags : byte
{
Locked = 0x01, Used = 0x80
}
struct FileEntry
{
/// <summary>0x00, Entry flags</summary>
public FileFlags flFlags;
/// <summary>0x01, Version number</summary>
public byte flTyp;
/// <summary>0x02, FinderInfo</summary>
public AppleCommon.FInfo flUsrWds;
/// <summary>0x12, file ID</summary>
public uint flFlNum;
/// <summary>0x16, first allocation block of data fork</summary>
public ushort flStBlk;
/// <summary>0x18, logical end-of-file of data fork</summary>
public uint flLgLen;
/// <summary>0x1C, physical end-of-file of data fork</summary>
public uint flPyLen;
/// <summary>0x20, first allocation block of resource fork</summary>
public ushort flRStBlk;
/// <summary>0x22, logical end-of-file of resource fork</summary>
public uint flRLgLen;
/// <summary>0x26, physical end-of-file of resource fork</summary>
public uint flRPyLen;
/// <summary>0x2A, date and time of creation</summary>
public uint flCrDat;
/// <summary>0x2E, date and time of last modification</summary>
public uint flMdDat;
/// <summary>0x32, file name prefixed with length</summary>
public byte[] flNam;
}
sealed class AppleMfsFileNode : IFileNode
{
internal byte[] _cache;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; set; }
}
sealed class AppleMfsDirNode : IDirNode
{
internal string[] _contents;
internal int _position;
/// <inheritdoc />
public string Path { get; init; }
}
#endregion
}

View File

@@ -43,9 +43,11 @@ public sealed partial class AppleMFS
{
const int BYTES_BEFORE_BLOCK_MAP = 64;
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
{
_device = imagePlugin;
_partitionStart = partition.Start;
@@ -86,7 +88,7 @@ public sealed partial class AppleMFS
_volMdb.drNxtFNum = BigEndianBitConverter.ToUInt32(_mdbBlocks, 0x01E);
_volMdb.drFreeBks = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x022);
_volMdb.drVNSiz = _mdbBlocks[0x024];
byte[] variableSize = new byte[_volMdb.drVNSiz + 1];
var variableSize = new byte[_volMdb.drVNSiz + 1];
Array.Copy(_mdbBlocks, 0x024, variableSize, 0, _volMdb.drVNSiz + 1);
_volMdb.drVN = StringHandlers.PascalToString(variableSize, _encoding);
@@ -95,11 +97,11 @@ public sealed partial class AppleMFS
if(errno != ErrorNumber.NoError)
return errno;
int bytesInBlockMap = (_volMdb.drNmAlBlks * 12 / 8) + (_volMdb.drNmAlBlks * 12 % 8);
int bytesInWholeMdb = bytesInBlockMap + BYTES_BEFORE_BLOCK_MAP;
int bytesInBlockMap = _volMdb.drNmAlBlks * 12 / 8 + _volMdb.drNmAlBlks * 12 % 8;
int bytesInWholeMdb = bytesInBlockMap + BYTES_BEFORE_BLOCK_MAP;
int sectorsInWholeMdb = (bytesInWholeMdb / (int)_device.Info.SectorSize) +
(bytesInWholeMdb % (int)_device.Info.SectorSize);
int sectorsInWholeMdb = bytesInWholeMdb / (int)_device.Info.SectorSize +
bytesInWholeMdb % (int)_device.Info.SectorSize;
errno = _device.ReadSectors(_partitionStart + 2, (uint)sectorsInWholeMdb, out byte[] wholeMdb);
@@ -109,10 +111,10 @@ public sealed partial class AppleMFS
_blockMapBytes = new byte[bytesInBlockMap];
Array.Copy(wholeMdb, BYTES_BEFORE_BLOCK_MAP, _blockMapBytes, 0, _blockMapBytes.Length);
int offset = 0;
var offset = 0;
_blockMap = new uint[_volMdb.drNmAlBlks + 2 + 1];
for(int i = 2; i < _volMdb.drNmAlBlks + 2; i += 8)
for(var i = 2; i < _volMdb.drNmAlBlks + 2; i += 8)
{
uint tmp1 = 0;
uint tmp2 = 0;
@@ -173,7 +175,7 @@ public sealed partial class AppleMFS
_mounted = true;
ushort bbSig = BigEndianBitConverter.ToUInt16(_bootBlocks, 0x000);
var bbSig = BigEndianBitConverter.ToUInt16(_bootBlocks, 0x000);
if(bbSig != AppleCommon.BB_MAGIC)
_bootBlocks = null;
@@ -181,18 +183,14 @@ public sealed partial class AppleMFS
Metadata = new FileSystem();
if(_volMdb.drLsBkUp > 0)
{
Metadata.BackupDate = DateHandlers.MacToDateTime(_volMdb.drLsBkUp);
}
Metadata.Bootable = bbSig == AppleCommon.BB_MAGIC;
Metadata.Clusters = _volMdb.drNmAlBlks;
Metadata.ClusterSize = _volMdb.drAlBlkSiz;
if(_volMdb.drCrDate > 0)
{
Metadata.CreationDate = DateHandlers.MacToDateTime(_volMdb.drCrDate);
}
Metadata.Files = _volMdb.drNmFls;
Metadata.FreeClusters = _volMdb.drFreeBks;
@@ -231,4 +229,6 @@ public sealed partial class AppleMFS
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -41,6 +41,8 @@ namespace Aaru.Filesystems;
// Information from Inside Macintosh Volume II
public sealed partial class AppleMFS
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber ListXAttr(string path, out List<string> xattrs)
{
@@ -49,10 +51,7 @@ public sealed partial class AppleMFS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -62,16 +61,18 @@ public sealed partial class AppleMFS
xattrs = new List<string>();
if(_debug)
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
{
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
{
if(_device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag))
xattrs.Add("com.apple.macintosh.tags");
return ErrorNumber.NoError;
}
}
if(!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
return ErrorNumber.NoSuchFile;
@@ -105,10 +106,7 @@ public sealed partial class AppleMFS
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -116,10 +114,12 @@ public sealed partial class AppleMFS
path = pathElements[0];
if(_debug)
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
{
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
{
if(_device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag) &&
string.Compare(xattr, "com.apple.macintosh.tags", StringComparison.InvariantCulture) == 0)
{
@@ -157,6 +157,8 @@ public sealed partial class AppleMFS
}
else
return ErrorNumber.NoSuchExtendedAttribute;
}
}
ErrorNumber error;
@@ -194,4 +196,6 @@ public sealed partial class AppleMFS
return error;
}
#endregion
}

View File

@@ -37,10 +37,16 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class AtheOS : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.AtheOS_Name;
/// <inheritdoc />
public Guid Id => new("AAB2C4F1-DC07-49EE-A948-576CC51B58C5");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -42,6 +42,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class AtheOS
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -60,14 +62,14 @@ public sealed partial class AtheOS
if(errno != ErrorNumber.NoError)
return false;
byte[] sbSector = new byte[AFS_SUPERBLOCK_SIZE];
var sbSector = new byte[AFS_SUPERBLOCK_SIZE];
if(offset + AFS_SUPERBLOCK_SIZE > tmp.Length)
return false;
Array.Copy(tmp, offset, sbSector, 0, AFS_SUPERBLOCK_SIZE);
uint magic = BitConverter.ToUInt32(sbSector, 0x20);
var magic = BitConverter.ToUInt32(sbSector, 0x20);
return magic == AFS_MAGIC1;
}
@@ -94,7 +96,7 @@ public sealed partial class AtheOS
if(errno != ErrorNumber.NoError)
return;
byte[] sbSector = new byte[AFS_SUPERBLOCK_SIZE];
var sbSector = new byte[AFS_SUPERBLOCK_SIZE];
Array.Copy(tmp, offset, sbSector, 0, AFS_SUPERBLOCK_SIZE);
SuperBlock afsSb = Marshal.ByteArrayToStructureLittleEndian<SuperBlock>(sbSector);
@@ -104,7 +106,7 @@ public sealed partial class AtheOS
if(afsSb.flags == 1)
sb.AppendLine(Localization.Filesystem_is_read_only);
sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(afsSb.name, encoding)).AppendLine();
sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(afsSb.name, encoding)).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_block, afsSb.block_size).AppendLine();
sb.AppendFormat(Localization._0_blocks_in_volume_1_bytes, afsSb.num_blocks,
@@ -128,19 +130,24 @@ public sealed partial class AtheOS
afsSb.log_size, afsSb.log_valid_blocks).AppendLine();
sb.
AppendFormat(Localization.Root_folder_s_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
afsSb.root_dir_start, afsSb.root_dir_ag, afsSb.root_dir_len,
afsSb.root_dir_len * afsSb.block_size).AppendLine();
AppendFormat(
Localization.
Root_folder_s_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
afsSb.root_dir_start, afsSb.root_dir_ag, afsSb.root_dir_len,
afsSb.root_dir_len * afsSb.block_size).AppendLine();
sb.
AppendFormat(Localization.Directory_containing_files_scheduled_for_deletion_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
afsSb.deleted_start, afsSb.deleted_ag, afsSb.deleted_len,
afsSb.deleted_len * afsSb.block_size).AppendLine();
AppendFormat(
Localization.
Directory_containing_files_scheduled_for_deletion_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
afsSb.deleted_start, afsSb.deleted_ag, afsSb.deleted_len,
afsSb.deleted_len * afsSb.block_size).AppendLine();
sb.
AppendFormat(Localization.Indices_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
afsSb.indices_start, afsSb.indices_ag, afsSb.indices_len,
afsSb.indices_len * afsSb.block_size).AppendLine();
AppendFormat(
Localization.Indices_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
afsSb.indices_start, afsSb.indices_ag, afsSb.indices_len,
afsSb.indices_len * afsSb.block_size).AppendLine();
sb.AppendFormat(Localization._0_blocks_for_bootloader_1_bytes, afsSb.boot_size,
afsSb.boot_size * afsSb.block_size).AppendLine();
@@ -157,4 +164,6 @@ public sealed partial class AtheOS
VolumeName = StringHandlers.CToString(afsSb.name, encoding)
};
}
#endregion
}

View File

@@ -36,6 +36,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class AtheOS
{
#region Nested type: SuperBlock
/// <summary>Be superblock</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct SuperBlock
@@ -102,4 +104,6 @@ public sealed partial class AtheOS
/// <summary>0x08C, Size of bootloader</summary>
public readonly int boot_size;
}
#endregion
}

View File

@@ -38,10 +38,16 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class BeFS : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.BeFS_Name;
/// <inheritdoc />
public Guid Id => new("dc8572b3-b6ad-46e4-8de9-cbe123ff6672");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -43,6 +43,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class BeFS
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -54,8 +56,8 @@ public sealed partial class BeFS
if(errno != ErrorNumber.NoError)
return false;
uint magic = BitConverter.ToUInt32(sbSector, 0x20);
uint magicBe = BigEndianBitConverter.ToUInt32(sbSector, 0x20);
var magic = BitConverter.ToUInt32(sbSector, 0x20);
var magicBe = BigEndianBitConverter.ToUInt32(sbSector, 0x20);
if(magic == BEFS_MAGIC1 ||
magicBe == BEFS_MAGIC1)
@@ -138,7 +140,8 @@ public sealed partial class BeFS
return;
}
besb = littleEndian ? Marshal.ByteArrayToStructureLittleEndian<SuperBlock>(sbSector)
besb = littleEndian
? Marshal.ByteArrayToStructureLittleEndian<SuperBlock>(sbSector)
: Marshal.ByteArrayToStructureBigEndian<SuperBlock>(sbSector);
sb.AppendLine(littleEndian ? Localization.Little_endian_BeFS : Localization.Big_endian_BeFS);
@@ -152,8 +155,8 @@ public sealed partial class BeFS
1 << (int)besb.block_shift != besb.block_size)
{
sb.AppendLine(Localization.Superblock_seems_corrupt_following_information_may_be_incorrect);
sb.AppendFormat(Localization.Magic_one_0_Should_be_0x42465331, besb.magic1).AppendLine();
sb.AppendFormat(Localization.Magic_two_0_Should_be_0xDD121031, besb.magic2).AppendLine();
sb.AppendFormat(Localization.Magic_one_0_Should_be_0x42465331, besb.magic1).AppendLine();
sb.AppendFormat(Localization.Magic_two_0_Should_be_0xDD121031, besb.magic2).AppendLine();
sb.AppendFormat(Localization.Magic_three_0_Should_be_0x15B6830E, besb.magic3).AppendLine();
sb.AppendFormat(Localization.Filesystem_endianness_0_Should_be_0x42494745, besb.fs_byte_order).AppendLine();
@@ -170,7 +173,8 @@ public sealed partial class BeFS
switch(besb.flags)
{
case BEFS_CLEAN:
sb.AppendLine(besb.log_start == besb.log_end ? Localization.Filesystem_is_clean
sb.AppendLine(besb.log_start == besb.log_end
? Localization.Filesystem_is_clean
: Localization.Filesystem_is_dirty);
break;
@@ -184,7 +188,7 @@ public sealed partial class BeFS
break;
}
sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(besb.name, encoding)).AppendLine();
sb.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(besb.name, encoding)).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_block, besb.block_size).AppendLine();
sb.AppendFormat(Localization._0_blocks_in_volume_1_bytes, besb.num_blocks, besb.num_blocks * besb.block_size).
@@ -208,13 +212,16 @@ public sealed partial class BeFS
AppendLine();
sb.
AppendFormat(Localization.Root_folder_s_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
besb.root_dir_start, besb.root_dir_ag, besb.root_dir_len, besb.root_dir_len * besb.block_size).
AppendFormat(
Localization.
Root_folder_s_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
besb.root_dir_start, besb.root_dir_ag, besb.root_dir_len, besb.root_dir_len * besb.block_size).
AppendLine();
sb.
AppendFormat(Localization.Indices_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
besb.indices_start, besb.indices_ag, besb.indices_len, besb.indices_len * besb.block_size).
AppendFormat(
Localization.Indices_i_node_resides_in_block_0_of_allocation_group_1_and_runs_for_2_blocks_3_bytes,
besb.indices_start, besb.indices_ag, besb.indices_len, besb.indices_len * besb.block_size).
AppendLine();
information = sb.ToString();
@@ -229,4 +236,6 @@ public sealed partial class BeFS
VolumeName = StringHandlers.CToString(besb.name, encoding)
};
}
#endregion
}

View File

@@ -37,6 +37,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class BeFS
{
#region Nested type: SuperBlock
/// <summary>Be superblock</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct SuperBlock
@@ -93,4 +95,6 @@ public sealed partial class BeFS
/// <summary>0x082, As this is part of inode_addr, this is 1</summary>
public readonly ushort indices_len;
}
#endregion
}

View File

@@ -39,11 +39,18 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the b-tree filesystem (btrfs)</summary>
public sealed partial class BTRFS : IFilesystem
{
const string MODULE_NAME = "BTRFS Plugin";
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.BTRFS_Name;
/// <inheritdoc />
public Guid Id => new("C904CF15-5222-446B-B7DB-02EAC5D781B3");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
const string MODULE_NAME = "BTRFS Plugin";
#endregion
}

View File

@@ -44,6 +44,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the b-tree filesystem (btrfs)</summary>
public sealed partial class BTRFS
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -72,10 +74,10 @@ public sealed partial class BTRFS
return false;
}
AaruConsole.DebugWriteLine(MODULE_NAME, "sbSectorOff = {0}", sbSectorOff);
AaruConsole.DebugWriteLine(MODULE_NAME, "sbSectorSize = {0}", sbSectorSize);
AaruConsole.DebugWriteLine(MODULE_NAME, "sbSectorOff = {0}", sbSectorOff);
AaruConsole.DebugWriteLine(MODULE_NAME, "sbSectorSize = {0}", sbSectorSize);
AaruConsole.DebugWriteLine(MODULE_NAME, "partition.PartitionStartSector = {0}", partition.Start);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.magic = 0x{0:X16}", btrfsSb.magic);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.magic = 0x{0:X16}", btrfsSb.magic);
return btrfsSb.magic == BTRFS_MAGIC;
}
@@ -98,39 +100,39 @@ public sealed partial class BTRFS
SuperBlock btrfsSb = Marshal.ByteArrayToStructureLittleEndian<SuperBlock>(sector);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.checksum = {0}", btrfsSb.checksum);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.uuid = {0}", btrfsSb.uuid);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.pba = {0}", btrfsSb.pba);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.flags = {0}", btrfsSb.flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.magic = {0}", btrfsSb.magic);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.generation = {0}", btrfsSb.generation);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.root_lba = {0}", btrfsSb.root_lba);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.chunk_lba = {0}", btrfsSb.chunk_lba);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_lba = {0}", btrfsSb.log_lba);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_root_transid = {0}", btrfsSb.log_root_transid);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.total_bytes = {0}", btrfsSb.total_bytes);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.bytes_used = {0}", btrfsSb.bytes_used);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.checksum = {0}", btrfsSb.checksum);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.uuid = {0}", btrfsSb.uuid);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.pba = {0}", btrfsSb.pba);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.flags = {0}", btrfsSb.flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.magic = {0}", btrfsSb.magic);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.generation = {0}", btrfsSb.generation);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.root_lba = {0}", btrfsSb.root_lba);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.chunk_lba = {0}", btrfsSb.chunk_lba);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_lba = {0}", btrfsSb.log_lba);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_root_transid = {0}", btrfsSb.log_root_transid);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.total_bytes = {0}", btrfsSb.total_bytes);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.bytes_used = {0}", btrfsSb.bytes_used);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.root_dir_objectid = {0}", btrfsSb.root_dir_objectid);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.num_devices = {0}", btrfsSb.num_devices);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.sectorsize = {0}", btrfsSb.sectorsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.nodesize = {0}", btrfsSb.nodesize);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.leafsize = {0}", btrfsSb.leafsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.stripesize = {0}", btrfsSb.stripesize);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.n = {0}", btrfsSb.n);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.num_devices = {0}", btrfsSb.num_devices);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.sectorsize = {0}", btrfsSb.sectorsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.nodesize = {0}", btrfsSb.nodesize);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.leafsize = {0}", btrfsSb.leafsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.stripesize = {0}", btrfsSb.stripesize);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.n = {0}", btrfsSb.n);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.chunk_root_generation = {0}",
btrfsSb.chunk_root_generation);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.compat_flags = 0x{0:X16}", btrfsSb.compat_flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.compat_flags = 0x{0:X16}", btrfsSb.compat_flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.compat_ro_flags = 0x{0:X16}", btrfsSb.compat_ro_flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.incompat_flags = 0x{0:X16}", btrfsSb.incompat_flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.csum_type = {0}", btrfsSb.csum_type);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.root_level = {0}", btrfsSb.root_level);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.chunk_root_level = {0}", btrfsSb.chunk_root_level);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_root_level = {0}", btrfsSb.log_root_level);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.id = 0x{0:X16}", btrfsSb.dev_item.id);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.bytes = {0}", btrfsSb.dev_item.bytes);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.used = {0}", btrfsSb.dev_item.used);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.incompat_flags = 0x{0:X16}", btrfsSb.incompat_flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.csum_type = {0}", btrfsSb.csum_type);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.root_level = {0}", btrfsSb.root_level);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.chunk_root_level = {0}", btrfsSb.chunk_root_level);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.log_root_level = {0}", btrfsSb.log_root_level);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.id = 0x{0:X16}", btrfsSb.dev_item.id);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.bytes = {0}", btrfsSb.dev_item.bytes);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.used = {0}", btrfsSb.dev_item.used);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.optimal_align = {0}",
btrfsSb.dev_item.optimal_align);
@@ -157,7 +159,7 @@ public sealed partial class BTRFS
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.device_uuid = {0}", btrfsSb.dev_item.device_uuid);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.dev_item.uuid = {0}", btrfsSb.dev_item.uuid);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.label = {0}", btrfsSb.label);
AaruConsole.DebugWriteLine(MODULE_NAME, "btrfsSb.label = {0}", btrfsSb.label);
sbInformation.AppendLine(Localization.B_tree_filesystem);
sbInformation.AppendFormat(Localization.UUID_0, btrfsSb.uuid).AppendLine();
@@ -169,17 +171,17 @@ public sealed partial class BTRFS
sbInformation.AppendFormat(Localization.Volume_has_0_bytes_spanned_in_1_devices, btrfsSb.total_bytes,
btrfsSb.num_devices).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_bytes_used, btrfsSb.bytes_used).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_sector, btrfsSb.sectorsize).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_node, btrfsSb.nodesize).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_leaf, btrfsSb.leafsize).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_stripe, btrfsSb.stripesize).AppendLine();
sbInformation.AppendFormat(Localization.Flags_0, btrfsSb.flags).AppendLine();
sbInformation.AppendFormat(Localization.Compatible_flags_0, btrfsSb.compat_flags).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_bytes_used, btrfsSb.bytes_used).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_sector, btrfsSb.sectorsize).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_node, btrfsSb.nodesize).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_leaf, btrfsSb.leafsize).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_stripe, btrfsSb.stripesize).AppendLine();
sbInformation.AppendFormat(Localization.Flags_0, btrfsSb.flags).AppendLine();
sbInformation.AppendFormat(Localization.Compatible_flags_0, btrfsSb.compat_flags).AppendLine();
sbInformation.AppendFormat(Localization.Read_only_compatible_flags_0, btrfsSb.compat_ro_flags).AppendLine();
sbInformation.AppendFormat(Localization.Incompatible_flags_0, btrfsSb.incompat_flags).AppendLine();
sbInformation.AppendFormat(Localization.Device_UUID_0, btrfsSb.dev_item.uuid).AppendLine();
sbInformation.AppendFormat(Localization.Volume_label_0, btrfsSb.label).AppendLine();
sbInformation.AppendFormat(Localization.Incompatible_flags_0, btrfsSb.incompat_flags).AppendLine();
sbInformation.AppendFormat(Localization.Device_UUID_0, btrfsSb.dev_item.uuid).AppendLine();
sbInformation.AppendFormat(Localization.Volume_label_0, btrfsSb.label).AppendLine();
information = sbInformation.ToString();
@@ -193,6 +195,8 @@ public sealed partial class BTRFS
Type = FS_TYPE
};
metadata.FreeClusters = metadata.Clusters - (btrfsSb.bytes_used / btrfsSb.sectorsize);
metadata.FreeClusters = metadata.Clusters - btrfsSb.bytes_used / btrfsSb.sectorsize;
}
#endregion
}

View File

@@ -39,6 +39,31 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the b-tree filesystem (btrfs)</summary>
public sealed partial class BTRFS
{
#region Nested type: DevItem
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DevItem
{
public readonly ulong id;
public readonly ulong bytes;
public readonly ulong used;
public readonly uint optimal_align;
public readonly uint optimal_width;
public readonly uint minimal_size;
public readonly ulong type;
public readonly ulong generation;
public readonly ulong start_offset;
public readonly uint dev_group;
public readonly byte seek_speed;
public readonly byte bandwidth;
public readonly Guid device_uuid;
public readonly Guid uuid;
}
#endregion
#region Nested type: SuperBlock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct SuperBlock
{
@@ -81,22 +106,5 @@ public sealed partial class BTRFS
public readonly byte[] unused;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DevItem
{
public readonly ulong id;
public readonly ulong bytes;
public readonly ulong used;
public readonly uint optimal_align;
public readonly uint optimal_width;
public readonly uint minimal_size;
public readonly ulong type;
public readonly ulong generation;
public readonly ulong start_offset;
public readonly uint dev_group;
public readonly byte seek_speed;
public readonly byte bandwidth;
public readonly Guid device_uuid;
public readonly Guid uuid;
}
#endregion
}

View File

@@ -35,10 +35,16 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the filesystem used in 8-bit Commodore microcomputers</summary>
public sealed partial class CBM : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.CBM_Name;
/// <inheritdoc />
public Guid Id => new("D104744E-A376-450C-BAC0-1347C93F983B");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -42,6 +42,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the filesystem used in 8-bit Commodore microcomputers</summary>
public sealed partial class CBM
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -119,20 +121,16 @@ public sealed partial class CBM
sbInformation.AppendFormat(Localization.Directory_starts_at_track_0_sector_1, cbmHdr.directoryTrack,
cbmHdr.directorySector).AppendLine();
sbInformation.AppendFormat(Localization.Disk_DOS_Version_0, Encoding.ASCII.GetString(new[]
{
cbmHdr.diskDosVersion
})).AppendLine();
sbInformation.AppendFormat(Localization.Disk_DOS_Version_0,
Encoding.ASCII.GetString(new[] { cbmHdr.diskDosVersion })).AppendLine();
sbInformation.AppendFormat(Localization.DOS_Version_0, Encoding.ASCII.GetString(new[]
{
cbmHdr.dosVersion
})).AppendLine();
sbInformation.
AppendFormat(Localization.DOS_Version_0, Encoding.ASCII.GetString(new[] { cbmHdr.dosVersion })).
AppendLine();
sbInformation.AppendFormat(Localization.Disk_Version_0, Encoding.ASCII.GetString(new[]
{
cbmHdr.diskVersion
})).AppendLine();
sbInformation.
AppendFormat(Localization.Disk_Version_0, Encoding.ASCII.GetString(new[] { cbmHdr.diskVersion })).
AppendLine();
sbInformation.AppendFormat(Localization.Disk_ID_0, cbmHdr.diskId).AppendLine();
@@ -157,10 +155,9 @@ public sealed partial class CBM
sbInformation.AppendFormat(Localization.Disk_DOS_type_0,
Encoding.ASCII.GetString(BitConverter.GetBytes(cbmBam.dosType))).AppendLine();
sbInformation.AppendFormat(Localization.DOS_Version_0, Encoding.ASCII.GetString(new[]
{
cbmBam.dosVersion
})).AppendLine();
sbInformation.
AppendFormat(Localization.DOS_Version_0, Encoding.ASCII.GetString(new[] { cbmBam.dosVersion })).
AppendLine();
sbInformation.AppendFormat(Localization.Disk_ID_0, cbmBam.diskId).AppendLine();
@@ -173,4 +170,6 @@ public sealed partial class CBM
information = sbInformation.ToString();
}
#endregion
}

View File

@@ -34,6 +34,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the filesystem used in 8-bit Commodore microcomputers</summary>
public sealed partial class CBM
{
#region Nested type: BAM
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct BAM
{
@@ -77,6 +79,10 @@ public sealed partial class CBM
public readonly byte[] freeCount;
}
#endregion
#region Nested type: Header
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct Header
{
@@ -104,4 +110,6 @@ public sealed partial class CBM
/// <summary>Filled with 0xA0</summary>
public readonly short fill3;
}
#endregion
}

View File

@@ -43,6 +43,7 @@ namespace Aaru.Filesystems;
/// <summary>Implements the CP/M filesystem</summary>
public sealed partial class CPM : IReadOnlyFilesystem
{
const string MODULE_NAME = "CP/M Plugin";
/// <summary>True if <see cref="Identify" /> thinks this is a CP/M filesystem</summary>
bool _cpmFound;
@@ -82,12 +83,17 @@ public sealed partial class CPM : IReadOnlyFilesystem
/// <summary>If <see cref="Identify" /> thinks this is a CP/M filesystem, this is the definition for it</summary>
CpmDefinition _workingDefinition;
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public FileSystem Metadata { get; private set; }
/// <inheritdoc />
public string Name => Localization.CPM_Name;
/// <inheritdoc />
public Guid Id => new("AA2B8585-41DF-4E3B-8A35-D1A935E2F8A1");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
@@ -98,5 +104,5 @@ public sealed partial class CPM : IReadOnlyFilesystem
/// <inheritdoc />
public Dictionary<string, string> Namespaces => null;
const string MODULE_NAME = "CP/M Plugin";
#endregion
}

View File

@@ -39,6 +39,8 @@ public sealed partial class CPM
// Do not translate
const string FS_TYPE = "cpmfs";
#region Nested type: FormatByte
/// <summary>Enumerates the format identification byte used by CP/M-86</summary>
enum FormatByte : byte
{
@@ -63,4 +65,6 @@ public sealed partial class CPM
/// <summary>3.5" double-density double-side 9 sectors/track</summary>
k720Alt = 0x94
}
#endregion
}

View File

@@ -50,8 +50,10 @@ public sealed partial class CPM
{
_definitions =
JsonSerializer.
Deserialize(Assembly.GetExecutingAssembly().GetManifestResourceStream("Aaru.Filesystems.CPM.cpmdefs.json") ?? new MemoryStream(),
typeof(CpmDefinitions), CpmDefinitionsContext.Default) as CpmDefinitions;
Deserialize(
Assembly.GetExecutingAssembly().
GetManifestResourceStream("Aaru.Filesystems.CPM.cpmdefs.json") ?? new MemoryStream(),
typeof(CpmDefinitions), CpmDefinitionsContext.Default) as CpmDefinitions;
if(_definitions is null)
return false;
@@ -67,7 +69,7 @@ public sealed partial class CPM
sectorIds = new int[def.sectorsPerTrack]
};
for(int i = 0; i < def.sectorsPerTrack; i++)
for(var i = 0; i < def.sectorsPerTrack; i++)
def.side1.sectorIds[i] = i + 1;
}
@@ -82,7 +84,7 @@ public sealed partial class CPM
sectorIds = new int[def.sectorsPerTrack]
};
for(int i = 0; i < def.sectorsPerTrack; i++)
for(var i = 0; i < def.sectorsPerTrack; i++)
def.side2.sectorIds[i] = i + 1;
}
}

View File

@@ -40,6 +40,8 @@ namespace Aaru.Filesystems;
public sealed partial class CPM
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber OpenDir(string path, out IDirNode node)
{
@@ -96,6 +98,8 @@ public sealed partial class CPM
return ErrorNumber.NoError;
}
#endregion
/// <summary>
/// Checks that the given directory blocks follow the CP/M filesystem directory specification Corrupted
/// directories will fail. FAT directories will false positive if all files start with 0x05, and do not use full
@@ -110,47 +114,56 @@ public sealed partial class CPM
if(directory == null)
return false;
int fileCount = 0;
var fileCount = 0;
for(int off = 0; off < directory.Length; off += 32)
for(var off = 0; off < directory.Length; off += 32)
{
DirectoryEntry entry = Marshal.ByteArrayToStructureLittleEndian<DirectoryEntry>(directory, off, 32);
if((entry.statusUser & 0x7F) < 0x20)
{
for(int f = 0; f < 8; f++)
for(var f = 0; f < 8; f++)
{
if(entry.filename[f] < 0x20 &&
entry.filename[f] != 0x00)
return false;
}
for(int e = 0; e < 3; e++)
for(var e = 0; e < 3; e++)
{
if(entry.extension[e] < 0x20 &&
entry.extension[e] != 0x00)
return false;
}
if(!ArrayHelpers.ArrayIsNullOrWhiteSpace(entry.filename))
fileCount++;
}
else
{
switch(entry.statusUser)
{
case 0x20:
{
for(int f = 0; f < 8; f++)
for(var f = 0; f < 8; f++)
{
if(entry.filename[f] < 0x20 &&
entry.filename[f] != 0x00)
return false;
}
for(int e = 0; e < 3; e++)
for(var e = 0; e < 3; e++)
{
if(entry.extension[e] < 0x20 &&
entry.extension[e] != 0x00)
return false;
}
_label = Encoding.ASCII.GetString(directory, off + 1, 11).Trim();
_labelCreationDate = new byte[4];
_labelUpdateDate = new byte[4];
Array.Copy(directory, off + 24, _labelCreationDate, 0, 4);
Array.Copy(directory, off + 28, _labelUpdateDate, 0, 4);
Array.Copy(directory, off + 28, _labelUpdateDate, 0, 4);
break;
}
@@ -163,6 +176,7 @@ public sealed partial class CPM
break;
}
}
}
return fileCount > 0;

View File

@@ -36,6 +36,8 @@ namespace Aaru.Filesystems;
public sealed partial class CPM
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber GetAttributes(string path, out FileAttributes attributes)
{
@@ -44,10 +46,7 @@ public sealed partial class CPM
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -77,10 +76,7 @@ public sealed partial class CPM
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -156,18 +152,18 @@ public sealed partial class CPM
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
if(!string.IsNullOrEmpty(path) &&
string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0)
return _statCache.TryGetValue(pathElements[0].ToUpperInvariant(), out stat) ? ErrorNumber.NoError
{
return _statCache.TryGetValue(pathElements[0].ToUpperInvariant(), out stat)
? ErrorNumber.NoError
: ErrorNumber.NoSuchFile;
}
stat = new FileEntryInfo
{
@@ -183,4 +179,6 @@ public sealed partial class CPM
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -46,6 +46,8 @@ namespace Aaru.Filesystems;
public sealed partial class CPM
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -154,8 +156,10 @@ public sealed partial class CPM
case MediaType.GENERIC_HDD:
case MediaType.FlashDrive:
case MediaType.MetaFloppy_Mod_I:
case MediaType.MetaFloppy_Mod_II: break;
default: return false;
case MediaType.MetaFloppy_Mod_II:
break;
default:
return false;
}
// This will try to identify a CP/M filesystem
@@ -180,11 +184,11 @@ public sealed partial class CPM
if(errno == ErrorNumber.NoError)
{
int amsSbOffset = 0;
var amsSbOffset = 0;
uint sig1 = BitConverter.ToUInt32(sector, 0x2B);
var sig1 = BitConverter.ToUInt32(sector, 0x2B);
uint sig2 = BitConverter.ToUInt32(sector, 0x33) & 0x00FFFFFF;
uint sig3 = BitConverter.ToUInt32(sector, 0x7C);
var sig3 = BitConverter.ToUInt32(sector, 0x7C);
// PCW16 extended boot record
if(sig1 == 0x4D2F5043 &&
@@ -197,13 +201,13 @@ public sealed partial class CPM
Marshal.ByteArrayToStructureLittleEndian<AmstradSuperBlock>(sector, amsSbOffset, 16);
// Check that format byte and sidedness indicate the same number of sizes
if((amsSb.format == 0 && (amsSb.sidedness & 0x02) == 0) ||
(amsSb.format == 2 && (amsSb.sidedness & 0x02) == 1) ||
(amsSb.format == 2 && (amsSb.sidedness & 0x02) == 2))
if(amsSb.format == 0 && (amsSb.sidedness & 0x02) == 0 ||
amsSb.format == 2 && (amsSb.sidedness & 0x02) == 1 ||
amsSb.format == 2 && (amsSb.sidedness & 0x02) == 2)
{
// Calculate device limits
ulong sides = (ulong)(amsSb.format == 0 ? 1 : 2);
ulong sectorCount = (ulong)(amsSb.tps * amsSb.spt * (byte)sides);
var sides = (ulong)(amsSb.format == 0 ? 1 : 2);
var sectorCount = (ulong)(amsSb.tps * amsSb.spt * (byte)sides);
sectorSize = (ulong)(128 << amsSb.psh);
// Compare device limits from superblock to real limits
@@ -221,7 +225,7 @@ public sealed partial class CPM
bsh = amsSb.bsh
};
for(int i = 0; i < _dpb.bsh; i++)
for(var i = 0; i < _dpb.bsh; i++)
_dpb.blm += (byte)Math.Pow(2, i);
if(sectorCount >= 1440)
@@ -240,11 +244,11 @@ public sealed partial class CPM
_dpb.off = amsSb.off;
_dpb.psh = amsSb.psh;
for(int i = 0; i < _dpb.psh; i++)
for(var i = 0; i < _dpb.psh; i++)
_dpb.phm += (byte)Math.Pow(2, i);
_dpb.spt = (ushort)(amsSb.spt * (sectorSize / 128));
uint directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / sectorSize);
_dpb.spt = (ushort)(amsSb.spt * (sectorSize / 128));
var directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / sectorSize);
imagePlugin.ReadSectors(firstDirectorySector + partition.Start, directoryLength,
out directory);
@@ -275,17 +279,17 @@ public sealed partial class CPM
}
};
for(int si = 0; si < amsSb.spt; si++)
for(var si = 0; si < amsSb.spt; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
if(amsSb.format == 2)
{
_workingDefinition.order = (amsSb.sidedness & 0x02) switch
{
1 => "SIDES",
2 => "CYLINDERS",
_ => null
};
{
1 => "SIDES",
2 => "CYLINDERS",
_ => null
};
_workingDefinition.side2 = new Side
{
@@ -293,7 +297,7 @@ public sealed partial class CPM
sectorIds = new int[amsSb.spt]
};
for(int si = 0; si < amsSb.spt; si++)
for(var si = 0; si < amsSb.spt; si++)
_workingDefinition.side2.sectorIds[si] = si + 1;
}
else
@@ -319,7 +323,7 @@ public sealed partial class CPM
ushort sum = 0;
// Sum of all 16-bit words that make this sector must be 0
for(int i = 0; i < sector.Length; i += 2)
for(var i = 0; i < sector.Length; i += 2)
sum += BitConverter.ToUInt16(sector, i);
// It may happen that there is a corrupted superblock
@@ -331,10 +335,10 @@ public sealed partial class CPM
// Calculate volume size
sectorSize = (ulong)(hddSb.recordsPerSector * 128);
ulong sectorsInPartition = (ulong)(hddSb.cylinders * hddSb.heads * hddSb.sectorsPerTrack);
var sectorsInPartition = (ulong)(hddSb.cylinders * hddSb.heads * hddSb.sectorsPerTrack);
ulong startingSector =
(ulong)(((hddSb.firstCylinder * hddSb.heads) + hddSb.heads) * hddSb.sectorsPerTrack);
var startingSector =
(ulong)((hddSb.firstCylinder * hddSb.heads + hddSb.heads) * hddSb.sectorsPerTrack);
// If volume size corresponds with working partition (this variant will be inside MBR partitioning)
if(sectorSize == imagePlugin.Info.SectorSize &&
@@ -365,7 +369,7 @@ public sealed partial class CPM
spt = hddSb.spt
};
uint directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / sectorSize);
var directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / sectorSize);
imagePlugin.ReadSectors(firstDirectorySector + partition.Start, directoryLength,
out directory);
@@ -406,10 +410,10 @@ public sealed partial class CPM
sofs = 0
};
for(int si = 0; si < hddSb.sectorsPerTrack; si++)
for(var si = 0; si < hddSb.sectorsPerTrack; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
for(int si = 0; si < hddSb.spt; si++)
for(var si = 0; si < hddSb.spt; si++)
_workingDefinition.side2.sectorIds[si] = si + 1;
}
}
@@ -429,11 +433,13 @@ public sealed partial class CPM
// Check for alternate location of format ID
if(sector.Last() == 0x00 ||
sector.Last() == 0xFF)
{
if(sector[0x40] == 0x94 ||
sector[0x40] == 0x26)
formatByte = sector[0x40];
else
formatByte = sector.Last();
}
else
formatByte = sector.Last();
@@ -495,7 +501,7 @@ public sealed partial class CPM
sofs = 0
};
for(int si = 0; si < 8; si++)
for(var si = 0; si < 8; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
}
@@ -555,10 +561,10 @@ public sealed partial class CPM
sofs = 0
};
for(int si = 0; si < 8; si++)
for(var si = 0; si < 8; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
for(int si = 0; si < 8; si++)
for(var si = 0; si < 8; si++)
_workingDefinition.side2.sectorIds[si] = si + 1;
}
@@ -620,10 +626,10 @@ public sealed partial class CPM
sofs = 0
};
for(int si = 0; si < 9; si++)
for(var si = 0; si < 9; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
for(int si = 0; si < 9; si++)
for(var si = 0; si < 9; si++)
_workingDefinition.side2.sectorIds[si] = si + 1;
}
@@ -684,10 +690,10 @@ public sealed partial class CPM
sofs = 0
};
for(int si = 0; si < 9; si++)
for(var si = 0; si < 9; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
for(int si = 0; si < 9; si++)
for(var si = 0; si < 9; si++)
_workingDefinition.side2.sectorIds[si] = si + 1;
}
@@ -747,10 +753,10 @@ public sealed partial class CPM
sofs = 0
};
for(int si = 0; si < 9; si++)
for(var si = 0; si < 9; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
for(int si = 0; si < 9; si++)
for(var si = 0; si < 9; si++)
_workingDefinition.side2.sectorIds[si] = si + 1;
}
@@ -810,10 +816,10 @@ public sealed partial class CPM
sofs = 0
};
for(int si = 0; si < 15; si++)
for(var si = 0; si < 15; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
for(int si = 0; si < 15; si++)
for(var si = 0; si < 15; si++)
_workingDefinition.side2.sectorIds[si] = si + 1;
}
@@ -873,10 +879,10 @@ public sealed partial class CPM
sofs = 0
};
for(int si = 0; si < 18; si++)
for(var si = 0; si < 18; si++)
_workingDefinition.side1.sectorIds[si] = si + 1;
for(int si = 0; si < 18; si++)
for(var si = 0; si < 18; si++)
_workingDefinition.side2.sectorIds[si] = si + 1;
}
@@ -885,7 +891,7 @@ public sealed partial class CPM
if(_cpmFound)
{
uint directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / imagePlugin.Info.SectorSize);
var directoryLength = (uint)(((ulong)_dpb.drm + 1) * 32 / imagePlugin.Info.SectorSize);
imagePlugin.ReadSectors(firstDirectorySector86 + partition.Start, directoryLength,
out directory);
@@ -920,10 +926,12 @@ public sealed partial class CPM
{
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Trying_all_known_definitions);
foreach(CpmDefinition def in from def in _definitions.definitions let sectors =
foreach(CpmDefinition def in from def in _definitions.definitions
let sectors =
(ulong)(def.cylinders * def.sides * def.sectorsPerTrack)
where sectors == imagePlugin.Info.Sectors &&
def.bytesPerSector == imagePlugin.Info.SectorSize select def)
def.bytesPerSector == imagePlugin.Info.SectorSize
select def)
{
// Definition seems to describe current disk, at least, same number of volume sectors and bytes per sector
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Trying_definition_0, def.comment);
@@ -940,7 +948,7 @@ public sealed partial class CPM
{
_sectorMask = new int[def.side1.sectorIds.Length];
for(int m = 0; m < _sectorMask.Length; m++)
for(var m = 0; m < _sectorMask.Length; m++)
_sectorMask[m] = def.side1.sectorIds[m] - def.side1.sectorIds[0];
}
else
@@ -950,27 +958,31 @@ public sealed partial class CPM
{
_sectorMask = new int[def.side1.sectorIds.Length + def.side2.sectorIds.Length];
for(int m = 0; m < def.side1.sectorIds.Length; m++)
for(var m = 0; m < def.side1.sectorIds.Length; m++)
_sectorMask[m] = def.side1.sectorIds[m] - def.side1.sectorIds[0];
// Skip first track (first side)
for(int m = 0; m < def.side2.sectorIds.Length; m++)
for(var m = 0; m < def.side2.sectorIds.Length; m++)
{
_sectorMask[m + def.side1.sectorIds.Length] =
def.side2.sectorIds[m] - def.side2.sectorIds[0] + def.side1.sectorIds.Length;
}
}
// Head changes after whole side
else if(string.Compare(def.order, "CYLINDERS",
StringComparison.InvariantCultureIgnoreCase) == 0)
{
for(int m = 0; m < def.side1.sectorIds.Length; m++)
for(var m = 0; m < def.side1.sectorIds.Length; m++)
_sectorMask[m] = def.side1.sectorIds[m] - def.side1.sectorIds[0];
// Skip first track (first side) and first track (second side)
for(int m = 0; m < def.side1.sectorIds.Length; m++)
for(var m = 0; m < def.side1.sectorIds.Length; m++)
{
_sectorMask[m + def.side1.sectorIds.Length] =
def.side1.sectorIds[m] - def.side1.sectorIds[0] + def.side1.sectorIds.Length +
def.side2.sectorIds.Length;
}
}
// TODO: Implement COLUMBIA ordering
@@ -1008,12 +1020,15 @@ public sealed partial class CPM
// Read the directory marked by this definition
var ms = new MemoryStream();
for(int p = 0; p < dirLen; p++)
for(var p = 0; p < dirLen; p++)
{
errno =
imagePlugin.
ReadSector((ulong)((int)offset + (int)partition.Start + (p / _sectorMask.Length * _sectorMask.Length) + _sectorMask[p % _sectorMask.Length]),
out byte[] dirSector);
ReadSector(
(ulong)((int)offset + (int)partition.Start +
p / _sectorMask.Length * _sectorMask.Length +
_sectorMask[p % _sectorMask.Length]),
out byte[] dirSector);
if(errno != ErrorNumber.NoError)
break;
@@ -1024,14 +1039,18 @@ public sealed partial class CPM
directory = ms.ToArray();
if(def.evenOdd)
{
AaruConsole.DebugWriteLine(MODULE_NAME,
Localization.
Definition_contains_EVEN_ODD_field_with_unknown_meaning_detection_may_be_wrong);
}
// Complement of the directory bytes if needed
if(def.complement)
for(int b = 0; b < directory.Length; b++)
{
for(var b = 0; b < directory.Length; b++)
directory[b] = (byte)(~directory[b] & 0xFF);
}
// Check the directory
if(CheckDir(directory))
@@ -1160,17 +1179,21 @@ public sealed partial class CPM
sb.AppendFormat(Localization.Volume_block_is_0_bytes, 128 << _dpb.bsh).AppendLine();
if(_dpb.dsm > 0)
{
sb.AppendFormat(Localization.Volume_contains_0_blocks_1_bytes, _dpb.dsm, _dpb.dsm * (128 << _dpb.bsh)).
AppendLine();
}
sb.AppendFormat(Localization.Volume_contains_0_directory_entries, _dpb.drm + 1).AppendLine();
if(_workingDefinition.sofs > 0)
sb.AppendFormat(Localization.Volume_reserves_0_sectors_for_system, _workingDefinition.sofs).AppendLine();
else
{
sb.AppendFormat(Localization.Volume_reserves_1_tracks_0_sectors_for_system,
_workingDefinition.ofs * _workingDefinition.sectorsPerTrack, _workingDefinition.ofs).
AppendLine();
}
if(_workingDefinition.side1.sectorIds.Length >= 2)
{
@@ -1187,8 +1210,10 @@ public sealed partial class CPM
int interleaveSide2 = _workingDefinition.side2.sectorIds[1] - _workingDefinition.side2.sectorIds[0];
if(interleaveSide2 > 1)
{
sb.AppendFormat(Localization.Side_one_uses_0_one_software_interleaving, interleaveSide2).
AppendLine();
}
}
switch(_workingDefinition.order)
@@ -1213,11 +1238,15 @@ public sealed partial class CPM
sb.AppendFormat(Localization.Device_uses_0_one_hardware_interleaving, _workingDefinition.skew).AppendLine();
if(_workingDefinition.sofs > 0)
{
sb.AppendLine($"BSH {_dpb.bsh} BLM {_dpb.blm} EXM {_dpb.exm} DSM {_dpb.dsm} DRM {_dpb.drm} AL0 {_dpb.al0
:X2}H AL1 {_dpb.al1:X2}H SOFS {_workingDefinition.sofs}");
}
else
{
sb.AppendLine($"BSH {_dpb.bsh} BLM {_dpb.blm} EXM {_dpb.exm} DSM {_dpb.dsm} DRM {_dpb.drm} AL0 {_dpb.al0
:X2}H AL1 {_dpb.al1:X2}H OFS {_workingDefinition.ofs}");
}
if(_label != null)
sb.AppendFormat(Localization.Volume_label_0, _label).AppendLine();
@@ -1229,12 +1258,16 @@ public sealed partial class CPM
sb.AppendLine(Localization.Volume_uses_third_party_timestamps);
if(_labelCreationDate != null)
{
sb.AppendFormat(Localization.Volume_created_on_0, DateHandlers.CpmToDateTime(_labelCreationDate)).
AppendLine();
}
if(_labelUpdateDate != null)
{
sb.AppendFormat(Localization.Volume_updated_on_0, DateHandlers.CpmToDateTime(_labelUpdateDate)).
AppendLine();
}
metadata = new FileSystem();
metadata.Bootable |= _workingDefinition.sofs > 0 || _workingDefinition.ofs > 0;
@@ -1246,18 +1279,16 @@ public sealed partial class CPM
metadata.Clusters = partition.End - partition.Start;
if(_labelCreationDate != null)
{
metadata.CreationDate = DateHandlers.CpmToDateTime(_labelCreationDate);
}
if(_labelUpdateDate != null)
{
metadata.ModificationDate = DateHandlers.CpmToDateTime(_labelUpdateDate);
}
metadata.Type = FS_TYPE;
metadata.VolumeName = _label;
information = sb.ToString();
}
#endregion
}

View File

@@ -40,35 +40,7 @@ namespace Aaru.Filesystems;
public sealed partial class CPM
{
/// <summary>Most of the times this structure is hard wired or generated by CP/M, not stored on disk</summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
sealed class DiscParameterBlock
{
/// <summary>First byte of allocation bitmap</summary>
public byte al0;
/// <summary>Second byte of allocation bitmap</summary>
public byte al1;
/// <summary>Block mask</summary>
public byte blm;
/// <summary>Block shift</summary>
public byte bsh;
/// <summary>Checksum vector size</summary>
public ushort cks;
/// <summary>Directory entries - 1</summary>
public ushort drm;
/// <summary>Blocks on disk - 1</summary>
public ushort dsm;
/// <summary>Extent mask</summary>
public byte exm;
/// <summary>Reserved tracks</summary>
public ushort off;
/// <summary>Physical sector mask</summary>
public byte phm;
/// <summary>Physical sector shift</summary>
public byte psh;
/// <summary>Sectors per track</summary>
public ushort spt;
}
#region Nested type: AmstradSuperBlock
/// <summary>Amstrad superblock, for PCW</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
@@ -108,6 +80,186 @@ public sealed partial class CPM
public readonly byte fiddle;
}
#endregion
#region Nested type: CpmDirNode
sealed class CpmDirNode : IDirNode
{
internal string[] _contents;
internal int _position;
#region IDirNode Members
/// <inheritdoc />
public string Path { get; init; }
#endregion
}
#endregion
#region Nested type: CpmFileNode
sealed class CpmFileNode : IFileNode
{
internal byte[] _cache;
#region IFileNode Members
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; set; }
#endregion
}
#endregion
#region Nested type: DateEntry
/// <summary>CP/M 3 timestamp entry</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DateEntry
{
/// <summary>Must be 0x21</summary>
public readonly byte signature;
/// <summary>File 1 create/access timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date1;
/// <summary>File 1 modification timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date2;
/// <summary>File 1 password mode</summary>
public readonly byte mode1;
public readonly byte zero1;
/// <summary>File 2 create/access timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date3;
/// <summary>File 2 modification timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date4;
/// <summary>File 2 password mode</summary>
public readonly byte mode2;
public readonly byte zero2;
/// <summary>File 3 create/access timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date5;
/// <summary>File 3 modification timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date6;
/// <summary>File 3 password mode</summary>
public readonly byte mode3;
public readonly ushort zero3;
}
#endregion
#region Nested type: DirectoryEntry
/// <summary>Directory entry for &lt;256 allocation blocks</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryEntry
{
/// <summary>User number. Bit 7 set in CP/M 1 means hidden</summary>
public readonly byte statusUser;
/// <summary>Filename and bit 7 as flags</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly byte[] filename;
/// <summary>Extension and bit 7 as flags</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] extension;
/// <summary>Low byte of extent number</summary>
public readonly byte extentCounter;
/// <summary>
/// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how
/// many bytes are free. It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
/// </summary>
public readonly byte lastRecordBytes;
/// <summary>High byte of extent number</summary>
public readonly byte extentCounterHigh;
/// <summary>How many records are used in this entry. 0x80 if all are used.</summary>
public readonly byte records;
/// <summary>Allocation blocks</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public readonly byte[] allocations;
}
#endregion
#region Nested type: DirectoryEntry16
/// <summary>Directory entry for &gt;256 allocation blocks</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryEntry16
{
/// <summary>User number. Bit 7 set in CP/M 1 means hidden</summary>
public readonly byte statusUser;
/// <summary>Filename and bit 7 as flags</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly byte[] filename;
/// <summary>Extension and bit 7 as flags</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] extension;
/// <summary>Low byte of extent number</summary>
public readonly byte extentCounter;
/// <summary>
/// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how
/// many bytes are free. It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
/// </summary>
public readonly byte lastRecordBytes;
/// <summary>High byte of extent number</summary>
public readonly byte extentCounterHigh;
/// <summary>How many records are used in this entry. 0x80 if all are used.</summary>
public readonly byte records;
/// <summary>Allocation blocks</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly ushort[] allocations;
}
#endregion
#region Nested type: DiscParameterBlock
/// <summary>Most of the times this structure is hard wired or generated by CP/M, not stored on disk</summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
sealed class DiscParameterBlock
{
/// <summary>First byte of allocation bitmap</summary>
public byte al0;
/// <summary>Second byte of allocation bitmap</summary>
public byte al1;
/// <summary>Block mask</summary>
public byte blm;
/// <summary>Block shift</summary>
public byte bsh;
/// <summary>Checksum vector size</summary>
public ushort cks;
/// <summary>Directory entries - 1</summary>
public ushort drm;
/// <summary>Blocks on disk - 1</summary>
public ushort dsm;
/// <summary>Extent mask</summary>
public byte exm;
/// <summary>Reserved tracks</summary>
public ushort off;
/// <summary>Physical sector mask</summary>
public byte phm;
/// <summary>Physical sector shift</summary>
public byte psh;
/// <summary>Sectors per track</summary>
public ushort spt;
}
#endregion
#region Nested type: HardDiskSuperBlock
/// <summary>Superblock found on CP/M-86 hard disk volumes</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct HardDiskSuperBlock
@@ -187,6 +339,10 @@ public sealed partial class CPM
public readonly ushort firstSub;
}
#endregion
#region Nested type: LabelEntry
/// <summary>Volume label entry</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct LabelEntry
@@ -216,40 +372,9 @@ public sealed partial class CPM
public readonly byte[] mtime;
}
/// <summary>CP/M 3 timestamp entry</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DateEntry
{
/// <summary>Must be 0x21</summary>
public readonly byte signature;
/// <summary>File 1 create/access timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date1;
/// <summary>File 1 modification timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date2;
/// <summary>File 1 password mode</summary>
public readonly byte mode1;
public readonly byte zero1;
/// <summary>File 2 create/access timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date3;
/// <summary>File 2 modification timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date4;
/// <summary>File 2 password mode</summary>
public readonly byte mode2;
public readonly byte zero2;
/// <summary>File 3 create/access timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date5;
/// <summary>File 3 modification timestamp</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] date6;
/// <summary>File 3 password mode</summary>
public readonly byte mode3;
public readonly ushort zero3;
}
#endregion
#region Nested type: PasswordEntry
/// <summary>Password entry</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
@@ -276,6 +401,10 @@ public sealed partial class CPM
public readonly byte[] reserved2;
}
#endregion
#region Nested type: TrdPartyDateEntry
/// <summary>Timestamp for Z80DOS or DOS+</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct TrdPartyDateEntry
@@ -312,78 +441,5 @@ public sealed partial class CPM
public readonly byte[] access3;
}
/// <summary>Directory entry for &lt;256 allocation blocks</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryEntry
{
/// <summary>User number. Bit 7 set in CP/M 1 means hidden</summary>
public readonly byte statusUser;
/// <summary>Filename and bit 7 as flags</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly byte[] filename;
/// <summary>Extension and bit 7 as flags</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] extension;
/// <summary>Low byte of extent number</summary>
public readonly byte extentCounter;
/// <summary>
/// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how
/// many bytes are free. It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
/// </summary>
public readonly byte lastRecordBytes;
/// <summary>High byte of extent number</summary>
public readonly byte extentCounterHigh;
/// <summary>How many records are used in this entry. 0x80 if all are used.</summary>
public readonly byte records;
/// <summary>Allocation blocks</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public readonly byte[] allocations;
}
/// <summary>Directory entry for &gt;256 allocation blocks</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryEntry16
{
/// <summary>User number. Bit 7 set in CP/M 1 means hidden</summary>
public readonly byte statusUser;
/// <summary>Filename and bit 7 as flags</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly byte[] filename;
/// <summary>Extension and bit 7 as flags</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] extension;
/// <summary>Low byte of extent number</summary>
public readonly byte extentCounter;
/// <summary>
/// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how
/// many bytes are free. It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
/// </summary>
public readonly byte lastRecordBytes;
/// <summary>High byte of extent number</summary>
public readonly byte extentCounterHigh;
/// <summary>How many records are used in this entry. 0x80 if all are used.</summary>
public readonly byte records;
/// <summary>Allocation blocks</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly ushort[] allocations;
}
sealed class CpmFileNode : IFileNode
{
internal byte[] _cache;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; set; }
}
sealed class CpmDirNode : IDirNode
{
internal string[] _contents;
internal int _position;
/// <inheritdoc />
public string Path { get; init; }
}
#endregion
}

View File

@@ -51,9 +51,11 @@ namespace Aaru.Filesystems;
public sealed partial class CPM
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
{
_device = imagePlugin;
_encoding = encoding ?? Encoding.GetEncoding("IBM437");
@@ -70,7 +72,7 @@ public sealed partial class CPM
{
_sectorMask = new int[_workingDefinition.side1.sectorIds.Length];
for(int m = 0; m < _sectorMask.Length; m++)
for(var m = 0; m < _sectorMask.Length; m++)
_sectorMask[m] = _workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0];
}
else
@@ -81,28 +83,32 @@ public sealed partial class CPM
_sectorMask = new int[_workingDefinition.side1.sectorIds.Length +
_workingDefinition.side2.sectorIds.Length];
for(int m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
for(var m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
_sectorMask[m] = _workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0];
// Skip first track (first side)
for(int m = 0; m < _workingDefinition.side2.sectorIds.Length; m++)
for(var m = 0; m < _workingDefinition.side2.sectorIds.Length; m++)
{
_sectorMask[m + _workingDefinition.side1.sectorIds.Length] =
_workingDefinition.side2.sectorIds[m] - _workingDefinition.side2.sectorIds[0] +
_workingDefinition.side1.sectorIds.Length;
}
}
// Head changes after whole side
else if(string.Compare(_workingDefinition.order, "CYLINDERS",
StringComparison.InvariantCultureIgnoreCase) == 0)
{
for(int m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
for(var m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
_sectorMask[m] = _workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0];
// Skip first track (first side) and first track (second side)
for(int m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
for(var m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
{
_sectorMask[m + _workingDefinition.side1.sectorIds.Length] =
_workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0] +
_workingDefinition.side1.sectorIds.Length + _workingDefinition.side2.sectorIds.Length;
}
// TODO: Implement CYLINDERS ordering
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.CYLINDERS_ordering_not_yet_implemented);
@@ -148,18 +154,22 @@ public sealed partial class CPM
{
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Deinterleaving_whole_volume);
for(int p = 0; p <= (int)(partition.End - partition.Start); p++)
for(var p = 0; p <= (int)(partition.End - partition.Start); p++)
{
ErrorNumber errno =
_device.ReadSector((ulong)((int)partition.Start + (p / _sectorMask.Length * _sectorMask.Length) + _sectorMask[p % _sectorMask.Length]),
out byte[] readSector);
_device.ReadSector(
(ulong)((int)partition.Start + p / _sectorMask.Length * _sectorMask.Length +
_sectorMask[p % _sectorMask.Length]),
out byte[] readSector);
if(errno != ErrorNumber.NoError)
return errno;
if(_workingDefinition.complement)
for(int b = 0; b < readSector.Length; b++)
{
for(var b = 0; b < readSector.Length; b++)
readSector[b] = (byte)(~readSector[b] & 0xFF);
}
deinterleavedSectors.Add((ulong)p, readSector);
}
@@ -168,7 +178,7 @@ public sealed partial class CPM
int blockSize = 128 << _dpb.bsh;
var blockMs = new MemoryStream();
ulong blockNo = 0;
int sectorsPerBlock = 0;
var sectorsPerBlock = 0;
Dictionary<ulong, byte[]> allocationBlocks = new();
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Creating_allocation_blocks);
@@ -180,12 +190,14 @@ public sealed partial class CPM
// May it happen? Just in case, CP/M blocks are smaller than physical sectors
if(sector.Length > blockSize)
for(int i = 0; i < sector.Length / blockSize; i++)
{
for(var i = 0; i < sector.Length / blockSize; i++)
{
byte[] tmp = new byte[blockSize];
var tmp = new byte[blockSize];
Array.Copy(sector, blockSize * i, tmp, 0, blockSize);
allocationBlocks.Add(blockNo++, tmp);
}
}
// CP/M blocks are larger than physical sectors
else if(sector.Length < blockSize)
@@ -219,7 +231,7 @@ public sealed partial class CPM
// Read the whole directory blocks
var dirMs = new MemoryStream();
for(int d = 0; d < dirSectors; d++)
for(var d = 0; d < dirSectors; d++)
{
deinterleavedSectors.TryGetValue((ulong)(d + dirOff), out byte[] sector);
dirMs.Write(sector, 0, sector.Length);
@@ -230,7 +242,7 @@ public sealed partial class CPM
if(directory == null)
return ErrorNumber.InvalidArgument;
int dirCnt = 0;
var dirCnt = 0;
string file1 = null;
string file2 = null;
string file3 = null;
@@ -239,7 +251,7 @@ public sealed partial class CPM
_statCache = new Dictionary<string, FileEntryInfo>();
_cpmStat = new FileSystemInfo();
bool atime = false;
var atime = false;
_dirList = new List<string>();
_labelCreationDate = null;
_labelUpdateDate = null;
@@ -248,8 +260,9 @@ public sealed partial class CPM
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Traversing_directory);
// For each directory entry
for(int dOff = 0; dOff < directory.Length; dOff += 32)
for(var dOff = 0; dOff < directory.Length; dOff += 32)
{
switch(directory[dOff] & 0x7F)
{
// Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries
@@ -265,15 +278,15 @@ public sealed partial class CPM
//bool backed = (entry.filename[3] & 0x80) == 0x80 || (entry.extension[3] & 0x80) == 0x80;
int user = entry.statusUser & 0x0F;
bool validEntry = true;
var validEntry = true;
for(int i = 0; i < 8; i++)
for(var i = 0; i < 8; i++)
{
entry.filename[i] &= 0x7F;
validEntry &= entry.filename[i] >= 0x20;
}
for(int i = 0; i < 3; i++)
for(var i = 0; i < 3; i++)
{
entry.extension[i] &= 0x7F;
validEntry &= entry.extension[i] >= 0x20;
@@ -294,16 +307,18 @@ public sealed partial class CPM
filename = filename.Replace('/', '\u2215');
int entryNo = ((32 * entry.extentCounter) + entry.extentCounterHigh) / (_dpb.exm + 1);
int entryNo = (32 * entry.extentCounter + entry.extentCounterHigh) / (_dpb.exm + 1);
// Do we have a stat for the file already?
if(_statCache.TryGetValue(filename, out FileEntryInfo fInfo))
_statCache.Remove(filename);
else
{
fInfo = new FileEntryInfo
{
Attributes = new FileAttributes()
};
}
// And any extent?
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks))
@@ -378,15 +393,15 @@ public sealed partial class CPM
//bool backed = (entry.filename[3] & 0x80) == 0x80 || (entry.extension[3] & 0x80) == 0x80;
int user = entry.statusUser & 0x0F;
bool validEntry = true;
var validEntry = true;
for(int i = 0; i < 8; i++)
for(var i = 0; i < 8; i++)
{
entry.filename[i] &= 0x7F;
validEntry &= entry.filename[i] >= 0x20;
}
for(int i = 0; i < 3; i++)
for(var i = 0; i < 3; i++)
{
entry.extension[i] &= 0x7F;
validEntry &= entry.extension[i] >= 0x20;
@@ -407,16 +422,18 @@ public sealed partial class CPM
filename = filename.Replace('/', '\u2215');
int entryNo = ((32 * entry.extentCounterHigh) + entry.extentCounter) / (_dpb.exm + 1);
int entryNo = (32 * entry.extentCounterHigh + entry.extentCounter) / (_dpb.exm + 1);
// Do we have a stat for the file already?
if(_statCache.TryGetValue(filename, out FileEntryInfo fInfo))
_statCache.Remove(filename);
else
{
fInfo = new FileEntryInfo
{
Attributes = new FileAttributes()
};
}
// And any extent?
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks))
@@ -487,10 +504,10 @@ public sealed partial class CPM
int user = entry.userNumber & 0x0F;
for(int i = 0; i < 8; i++)
for(var i = 0; i < 8; i++)
entry.filename[i] &= 0x7F;
for(int i = 0; i < 3; i++)
for(var i = 0; i < 3; i++)
entry.extension[i] &= 0x7F;
string filename = Encoding.ASCII.GetString(entry.filename).Trim();
@@ -510,7 +527,7 @@ public sealed partial class CPM
_passwordCache.Remove(filename);
// Copy whole password entry
byte[] tmp = new byte[32];
var tmp = new byte[32];
Array.Copy(directory, dOff, tmp, 0, 32);
_passwordCache.Add(filename, tmp);
@@ -552,7 +569,7 @@ public sealed partial class CPM
_labelCreationDate = new byte[4];
_labelUpdateDate = new byte[4];
Array.Copy(directory, dOff + 24, _labelCreationDate, 0, 4);
Array.Copy(directory, dOff + 28, _labelUpdateDate, 0, 4);
Array.Copy(directory, dOff + 28, _labelUpdateDate, 0, 4);
// Count entries 3 by 3 for timestamps
switch(dirCnt % 3)
@@ -659,7 +676,7 @@ public sealed partial class CPM
else
fInfo = new FileEntryInfo();
byte[] ctime = new byte[4];
var ctime = new byte[4];
ctime[0] = trdPartyDateEntry.create1[0];
ctime[1] = trdPartyDateEntry.create1[1];
@@ -677,7 +694,7 @@ public sealed partial class CPM
else
fInfo = new FileEntryInfo();
byte[] ctime = new byte[4];
var ctime = new byte[4];
ctime[0] = trdPartyDateEntry.create2[0];
ctime[1] = trdPartyDateEntry.create2[1];
@@ -695,7 +712,7 @@ public sealed partial class CPM
else
fInfo = new FileEntryInfo();
byte[] ctime = new byte[4];
var ctime = new byte[4];
ctime[0] = trdPartyDateEntry.create3[0];
ctime[1] = trdPartyDateEntry.create3[1];
@@ -717,6 +734,7 @@ public sealed partial class CPM
break;
}
}
// Cache all files. As CP/M maximum volume size is 8 Mib
// this should not be a problem
@@ -734,7 +752,8 @@ public sealed partial class CPM
fInfo.Blocks = 0;
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extents))
for(int ex = 0; ex < extents.Count; ex++)
{
for(var ex = 0; ex < extents.Count; ex++)
{
if(!extents.TryGetValue(ex, out List<ushort> alBlks))
continue;
@@ -746,6 +765,7 @@ public sealed partial class CPM
fInfo.Blocks++;
}
}
}
// If you insist to call CP/M "extent based"
fInfo.Attributes |= FileAttributes.Extents;
@@ -762,16 +782,18 @@ public sealed partial class CPM
// For each stored password, store a decoded version of it
if(_passwordCache.Count > 0)
{
foreach(KeyValuePair<string, byte[]> kvp in _passwordCache)
{
byte[] tmp = new byte[8];
var tmp = new byte[8];
Array.Copy(kvp.Value, 16, tmp, 0, 8);
for(int t = 0; t < 8; t++)
for(var t = 0; t < 8; t++)
tmp[t] ^= kvp.Value[13];
_decodedPasswordCache.Add(kvp.Key, tmp);
}
}
// Generate statfs.
_cpmStat.Blocks = (ulong)(_dpb.dsm + 1);
@@ -792,14 +814,10 @@ public sealed partial class CPM
};
if(_labelCreationDate != null)
{
Metadata.CreationDate = DateHandlers.CpmToDateTime(_labelCreationDate);
}
if(_labelUpdateDate != null)
{
Metadata.ModificationDate = DateHandlers.CpmToDateTime(_labelUpdateDate);
}
if(!string.IsNullOrEmpty(_label))
Metadata.VolumeName = _label;
@@ -839,4 +857,6 @@ public sealed partial class CPM
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -38,16 +38,15 @@ namespace Aaru.Filesystems;
public sealed partial class CPM
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber GetXattr(string path, string xattr, ref byte[] buf)
{
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -56,13 +55,16 @@ public sealed partial class CPM
return ErrorNumber.NoSuchFile;
if(string.Compare(xattr, "com.caldera.cpm.password", StringComparison.InvariantCulture) == 0)
{
if(!_passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf))
return ErrorNumber.NoError;
}
if(string.Compare(xattr, "com.caldera.cpm.password.text", StringComparison.InvariantCulture) != 0)
return ErrorNumber.NoSuchExtendedAttribute;
return !_passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf) ? ErrorNumber.NoError
return !_passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf)
? ErrorNumber.NoError
: ErrorNumber.NoSuchExtendedAttribute;
}
@@ -74,10 +76,7 @@ public sealed partial class CPM
if(!_mounted)
return ErrorNumber.AccessDenied;
string[] pathElements = path.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pathElements.Length != 1)
return ErrorNumber.NotSupported;
@@ -95,4 +94,6 @@ public sealed partial class CPM
return ErrorNumber.NoError;
}
#endregion
}

File diff suppressed because it is too large Load Diff

View File

@@ -39,10 +39,16 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedType.Local")]
public sealed partial class Cram : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.Cram_Name;
/// <inheritdoc />
public Guid Id => new("F8F6E46F-7A2A-48E3-9C0A-46AF4DC29E09");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -37,9 +37,16 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedType.Local")]
public sealed partial class Cram
{
#region Nested type: CramCompression
enum CramCompression : ushort
{
Zlib = 1, Lzma = 2, Lzo = 3,
Xz = 4, Lz4 = 5
Zlib = 1,
Lzma = 2,
Lzo = 3,
Xz = 4,
Lz4 = 5
}
#endregion
}

View File

@@ -44,6 +44,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedType.Local")]
public sealed partial class Cram
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -55,7 +57,7 @@ public sealed partial class Cram
if(errno != ErrorNumber.NoError)
return false;
uint magic = BitConverter.ToUInt32(sector, 0x00);
var magic = BitConverter.ToUInt32(sector, 0x00);
return magic is CRAM_MAGIC or CRAM_CIGAM;
}
@@ -72,10 +74,10 @@ public sealed partial class Cram
if(errno != ErrorNumber.NoError)
return;
uint magic = BitConverter.ToUInt32(sector, 0x00);
var magic = BitConverter.ToUInt32(sector, 0x00);
var crSb = new SuperBlock();
bool littleEndian = true;
var crSb = new SuperBlock();
var littleEndian = true;
switch(magic)
{
@@ -99,9 +101,9 @@ public sealed partial class Cram
sbInformation.AppendFormat(Localization.Volume_name_0, StringHandlers.CToString(crSb.name, encoding)).
AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_bytes, crSb.size).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_bytes, crSb.size).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_blocks, crSb.blocks).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_files, crSb.files).AppendLine();
sbInformation.AppendFormat(Localization.Volume_has_0_files, crSb.files).AppendLine();
information = sbInformation.ToString();
@@ -114,4 +116,6 @@ public sealed partial class Cram
FreeClusters = 0
};
}
#endregion
}

View File

@@ -38,6 +38,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedType.Local")]
public sealed partial class Cram
{
#region Nested type: SuperBlock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct SuperBlock
{
@@ -54,4 +56,6 @@ public sealed partial class Cram
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public readonly byte[] name;
}
#endregion
}

View File

@@ -39,10 +39,16 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the filesystem described in ECMA-67</summary>
public sealed partial class ECMA67 : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.ECMA67_Name;
/// <inheritdoc />
public Guid Id => new("62A2D44A-CBC1-4377-B4B6-28C5C92034A1");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -44,6 +44,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the filesystem described in ECMA-67</summary>
public sealed partial class ECMA67
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -98,4 +100,6 @@ public sealed partial class ECMA67
information = sbInformation.ToString();
}
#endregion
}

View File

@@ -38,6 +38,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection of the filesystem described in ECMA-67</summary>
public sealed partial class ECMA67
{
#region Nested type: VolumeLabel
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct VolumeLabel
{
@@ -64,4 +66,6 @@ public sealed partial class ECMA67
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)]
public readonly byte[] reserved5;
}
#endregion
}

View File

@@ -35,11 +35,18 @@ namespace Aaru.Filesystems;
/// <summary>Implements identification for the SGI Extent FileSystem</summary>
public sealed partial class EFS : IFilesystem
{
const string MODULE_NAME = "EFS plugin";
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.EFS_Name;
/// <inheritdoc />
public Guid Id => new("52A43F90-9AF3-4391-ADFE-65598DEEABAB");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
const string MODULE_NAME = "EFS plugin";
#endregion
}

View File

@@ -41,6 +41,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements identification for the SGI Extent FileSystem</summary>
public sealed partial class EFS
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -50,7 +52,7 @@ public sealed partial class EFS
// Misaligned
if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc)
{
uint sbSize = (uint)((Marshal.SizeOf<Superblock>() + 0x200) / imagePlugin.Info.SectorSize);
var sbSize = (uint)((Marshal.SizeOf<Superblock>() + 0x200) / imagePlugin.Info.SectorSize);
if((Marshal.SizeOf<Superblock>() + 0x200) % imagePlugin.Info.SectorSize != 0)
sbSize++;
@@ -63,7 +65,7 @@ public sealed partial class EFS
if(sector.Length < Marshal.SizeOf<Superblock>())
return false;
byte[] sbpiece = new byte[Marshal.SizeOf<Superblock>()];
var sbpiece = new byte[Marshal.SizeOf<Superblock>()];
Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf<Superblock>());
@@ -77,7 +79,7 @@ public sealed partial class EFS
}
else
{
uint sbSize = (uint)(Marshal.SizeOf<Superblock>() / imagePlugin.Info.SectorSize);
var sbSize = (uint)(Marshal.SizeOf<Superblock>() / imagePlugin.Info.SectorSize);
if(Marshal.SizeOf<Superblock>() % imagePlugin.Info.SectorSize != 0)
sbSize++;
@@ -118,7 +120,7 @@ public sealed partial class EFS
// Misaligned
if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc)
{
uint sbSize = (uint)((Marshal.SizeOf<Superblock>() + 0x400) / imagePlugin.Info.SectorSize);
var sbSize = (uint)((Marshal.SizeOf<Superblock>() + 0x400) / imagePlugin.Info.SectorSize);
if((Marshal.SizeOf<Superblock>() + 0x400) % imagePlugin.Info.SectorSize != 0)
sbSize++;
@@ -131,7 +133,7 @@ public sealed partial class EFS
if(sector.Length < Marshal.SizeOf<Superblock>())
return;
byte[] sbpiece = new byte[Marshal.SizeOf<Superblock>()];
var sbpiece = new byte[Marshal.SizeOf<Superblock>()];
Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf<Superblock>());
@@ -142,7 +144,7 @@ public sealed partial class EFS
}
else
{
uint sbSize = (uint)(Marshal.SizeOf<Superblock>() / imagePlugin.Info.SectorSize);
var sbSize = (uint)(Marshal.SizeOf<Superblock>() / imagePlugin.Info.SectorSize);
if(Marshal.SizeOf<Superblock>() % imagePlugin.Info.SectorSize != 0)
sbSize++;
@@ -214,4 +216,6 @@ public sealed partial class EFS
CreationDate = DateHandlers.UnixToDateTime(efsSb.sb_time)
};
}
#endregion
}

View File

@@ -35,7 +35,10 @@ namespace Aaru.Filesystems;
/// <summary>Implements identification for the SGI Extent FileSystem</summary>
public sealed partial class EFS
{
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "InconsistentNaming")]
#region Nested type: Superblock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[SuppressMessage("ReSharper", "InconsistentNaming")]
readonly struct Superblock
{
/* 0: fs size incl. bb 0 (in bb) */
@@ -84,4 +87,6 @@ public sealed partial class EFS
/* 88: checksum (all above) */
public readonly uint sb_checksum;
}
#endregion
}

View File

@@ -35,6 +35,7 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class F2FS
{
const string FS_TYPE = "f2fs";
// ReSharper disable InconsistentNaming
const uint F2FS_MAGIC = 0xF2F52010;
const uint F2FS_SUPER_OFFSET = 1024;
@@ -43,6 +44,4 @@ public sealed partial class F2FS
const uint F2FS_BLOCK_SIZE = 4096;
// ReSharper restore InconsistentNaming
const string FS_TYPE = "f2fs";
}

View File

@@ -37,10 +37,16 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class F2FS : IFilesystem
{
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.F2FS_Name;
/// <inheritdoc />
public Guid Id => new("82B0920F-5F0D-4063-9F57-ADE0AE02ECE5");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
#endregion
}

View File

@@ -41,6 +41,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class F2FS
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -52,7 +54,7 @@ public sealed partial class F2FS
if(sbAddr == 0)
sbAddr = 1;
uint sbSize = (uint)(Marshal.SizeOf<Superblock>() / imagePlugin.Info.SectorSize);
var sbSize = (uint)(Marshal.SizeOf<Superblock>() / imagePlugin.Info.SectorSize);
if(Marshal.SizeOf<Superblock>() % imagePlugin.Info.SectorSize != 0)
sbSize++;
@@ -88,7 +90,7 @@ public sealed partial class F2FS
if(sbAddr == 0)
sbAddr = 1;
uint sbSize = (uint)(Marshal.SizeOf<Superblock>() / imagePlugin.Info.SectorSize);
var sbSize = (uint)(Marshal.SizeOf<Superblock>() / imagePlugin.Info.SectorSize);
if(Marshal.SizeOf<Superblock>() % imagePlugin.Info.SectorSize != 0)
sbSize++;
@@ -110,20 +112,20 @@ public sealed partial class F2FS
var sb = new StringBuilder();
sb.AppendLine(Localization.F2FS_filesystem);
sb.AppendFormat(Localization.Version_0_1, f2fsSb.major_ver, f2fsSb.minor_ver).AppendLine();
sb.AppendFormat(Localization.Version_0_1, f2fsSb.major_ver, f2fsSb.minor_ver).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_sector, 1 << (int)f2fsSb.log_sectorsize).AppendLine();
sb.AppendFormat(Localization._0_sectors_1_bytes_per_block, 1 << (int)f2fsSb.log_sectors_per_block,
1 << (int)f2fsSb.log_blocksize).AppendLine();
sb.AppendFormat(Localization._0_blocks_per_segment, f2fsSb.log_blocks_per_seg).AppendLine();
sb.AppendFormat(Localization._0_blocks_in_volume, f2fsSb.block_count).AppendLine();
sb.AppendFormat(Localization._0_segments_per_section, f2fsSb.segs_per_sec).AppendLine();
sb.AppendFormat(Localization._0_sections_per_zone, f2fsSb.secs_per_zone).AppendLine();
sb.AppendFormat(Localization._0_sections, f2fsSb.section_count).AppendLine();
sb.AppendFormat(Localization._0_segments, f2fsSb.segment_count).AppendLine();
sb.AppendFormat(Localization._0_blocks_per_segment, f2fsSb.log_blocks_per_seg).AppendLine();
sb.AppendFormat(Localization._0_blocks_in_volume, f2fsSb.block_count).AppendLine();
sb.AppendFormat(Localization._0_segments_per_section, f2fsSb.segs_per_sec).AppendLine();
sb.AppendFormat(Localization._0_sections_per_zone, f2fsSb.secs_per_zone).AppendLine();
sb.AppendFormat(Localization._0_sections, f2fsSb.section_count).AppendLine();
sb.AppendFormat(Localization._0_segments, f2fsSb.segment_count).AppendLine();
sb.AppendFormat(Localization.Root_directory_resides_on_inode_0, f2fsSb.root_ino).AppendLine();
sb.AppendFormat(Localization.Volume_UUID_0, f2fsSb.uuid).AppendLine();
sb.AppendFormat(Localization.Volume_UUID_0, f2fsSb.uuid).AppendLine();
sb.AppendFormat(Localization.Volume_name_0,
StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true)).AppendLine();
@@ -147,4 +149,6 @@ public sealed partial class F2FS
VolumeSerial = f2fsSb.uuid.ToString()
};
}
#endregion
}

View File

@@ -37,7 +37,10 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public sealed partial class F2FS
{
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "InconsistentNaming")]
#region Nested type: Superblock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[SuppressMessage("ReSharper", "InconsistentNaming")]
readonly struct Superblock
{
public readonly uint magic;
@@ -99,4 +102,6 @@ public sealed partial class F2FS
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 871)]
public readonly byte[] reserved;
}
#endregion
}

View File

@@ -55,8 +55,9 @@ public sealed partial class FAT
ulong expectedClusters = humanBpb.bpc > 0 ? partition.Size / humanBpb.bpc : 0;
// Check clusters for Human68k are correct
bool humanClustersCorrect = humanBpb.clusters == 0 ? humanBpb.big_clusters == expectedClusters
: humanBpb.clusters == expectedClusters;
bool humanClustersCorrect = humanBpb.clusters == 0
? humanBpb.big_clusters == expectedClusters
: humanBpb.clusters == expectedClusters;
// Check OEM for Human68k is correct
bool humanOemCorrect = bpbSector[2] >= 0x20 && bpbSector[3] >= 0x20 && bpbSector[4] >= 0x20 &&
@@ -70,8 +71,8 @@ public sealed partial class FAT
bool humanBranchCorrect = bpbSector[0] == 0x60 && bpbSector[1] >= 0x1C && bpbSector[1] < 0xFE;
AaruConsole.DebugWriteLine(MODULE_NAME, "humanClustersCorrect = {0}", humanClustersCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "humanOemCorrect = {0}", humanOemCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "humanBranchCorrect = {0}", humanBranchCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "humanOemCorrect = {0}", humanOemCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "humanBranchCorrect = {0}", humanBranchCorrect);
// If all Human68k checks are correct, it is a Human68k FAT16
bool useHumanBpb = humanClustersCorrect && humanOemCorrect && humanBranchCorrect && expectedClusters > 0;
@@ -105,18 +106,18 @@ public sealed partial class FAT
var ebpb = new BiosParameterBlockEbpb();
var apricotBpb = new ApricotLabel();
bool useAtariBpb = false;
bool useMsxBpb = false;
bool useDos2Bpb = false;
bool useDos3Bpb = false;
bool useDos32Bpb = false;
bool useDos33Bpb = false;
bool userShortExtendedBpb = false;
bool useExtendedBpb = false;
bool useShortFat32 = false;
bool useLongFat32 = false;
bool useApricotBpb = false;
bool useDecRainbowBpb = false;
var useAtariBpb = false;
var useMsxBpb = false;
var useDos2Bpb = false;
var useDos3Bpb = false;
var useDos32Bpb = false;
var useDos33Bpb = false;
var userShortExtendedBpb = false;
var useExtendedBpb = false;
var useShortFat32 = false;
var useLongFat32 = false;
var useApricotBpb = false;
var useDecRainbowBpb = false;
if(imagePlugin.Info.SectorSize >= 256)
{
@@ -232,6 +233,7 @@ public sealed partial class FAT
if(ebpb.sectors == 0)
{
if(ebpb.big_sectors <= partition.End - partition.Start + 1)
{
if(ebpb.signature == 0x29 || andosOemCorrect)
{
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_4_0_BPB);
@@ -244,8 +246,10 @@ public sealed partial class FAT
userShortExtendedBpb = true;
minBootNearJump = 0x29;
}
}
}
else if(ebpb.sectors <= partition.End - partition.Start + 1)
{
if(ebpb.signature == 0x29 || andosOemCorrect)
{
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_DOS_4_0_BPB);
@@ -258,12 +262,14 @@ public sealed partial class FAT
userShortExtendedBpb = true;
minBootNearJump = 0x29;
}
}
}
else if(bitsInBpsDos33 == 1 &&
correctSpcDos33 &&
dos33Bpb.rsectors < partition.End - partition.Start &&
dos33Bpb.fats_no <= 2 &&
dos33Bpb is { root_ent: > 0, spfat: > 0 })
{
if(dos33Bpb.sectors == 0 &&
dos33Bpb.hsectors <= partition.Start &&
dos33Bpb.big_sectors > 0 &&
@@ -277,9 +283,10 @@ public sealed partial class FAT
dos33Bpb.hsectors <= partition.Start &&
dos33Bpb.sectors > 0 &&
dos33Bpb.sectors <= partition.End - partition.Start + 1)
{
if(atariBpb.jump[0] == 0x60 ||
(atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 &&
Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ") ||
atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 &&
Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT " ||
partition.Type is "GEM" or "BGM")
{
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_Atari_BPB);
@@ -291,6 +298,7 @@ public sealed partial class FAT
useDos33Bpb = true;
minBootNearJump = 0x22;
}
}
else
{
if(dos32Bpb.hsectors <= partition.Start &&
@@ -302,9 +310,10 @@ public sealed partial class FAT
}
else if(dos30Bpb.sptrk is > 0 and < 64 &&
dos30Bpb.heads is > 0 and < 256)
{
if(atariBpb.jump[0] == 0x60 ||
(atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 &&
Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT "))
atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 &&
Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ")
{
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_Atari_BPB);
useAtariBpb = true;
@@ -315,11 +324,12 @@ public sealed partial class FAT
useDos3Bpb = true;
minBootNearJump = 0x1C;
}
}
else
{
if(atariBpb.jump[0] == 0x60 ||
(atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 &&
Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT "))
atariBpb.jump[0] == 0xE9 && atariBpb.jump[1] == 0x00 &&
Encoding.ASCII.GetString(dos33Bpb.oem_name) != "NEXT ")
{
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Using_Atari_BPB);
useAtariBpb = true;
@@ -332,6 +342,7 @@ public sealed partial class FAT
}
}
}
}
}
// DEC Rainbow, lacks a BPB but has a very concrete structure...
@@ -361,30 +372,29 @@ public sealed partial class FAT
// Volume is software interleaved 2:1
var rootMs = new MemoryStream();
foreach(ulong rootSector in new ulong[]
{
0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20
})
foreach(ulong rootSector in new ulong[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 })
{
imagePlugin.ReadSector(rootSector, out byte[] tmp);
rootMs.Write(tmp, 0, tmp.Length);
}
byte[] rootDir = rootMs.ToArray();
bool validRootDir = true;
var validRootDir = true;
// Iterate all root directory
for(int e = 0; e < 96 * 32; e += 32)
for(var e = 0; e < 96 * 32; e += 32)
{
for(int c = 0; c < 11; c++)
if((rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05) ||
rootDir[c + e] == 0xFF ||
for(var c = 0; c < 11; c++)
{
if(rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05 ||
rootDir[c + e] == 0xFF ||
rootDir[c + e] == 0x2E)
{
validRootDir = false;
break;
}
}
if(!validRootDir)
break;
@@ -603,8 +613,8 @@ public sealed partial class FAT
}
// This assumes a bootable sector will jump somewhere or disable interrupts in x86 code
bootable |= bpbSector[0] == 0xFA || (bpbSector[0] == 0xEB && bpbSector[1] <= 0x7F) ||
(bpbSector[0] == 0xE9 && BitConverter.ToUInt16(bpbSector, 1) <= 0x1FC);
bootable |= bpbSector[0] == 0xFA || bpbSector[0] == 0xEB && bpbSector[1] <= 0x7F ||
bpbSector[0] == 0xE9 && BitConverter.ToUInt16(bpbSector, 1) <= 0x1FC;
fakeBpb.boot_code = bpbSector;
@@ -786,9 +796,11 @@ public sealed partial class FAT
if(apricotBpb.bootLocation > 0 &&
apricotBpb.bootLocation + apricotBpb.bootSize < imagePlugin.Info.Sectors)
{
imagePlugin.ReadSectors(apricotBpb.bootLocation,
(uint)(apricotBpb.sectorSize * apricotBpb.bootSize) / imagePlugin.Info.SectorSize,
out fakeBpb.boot_code);
}
return BpbKind.Apricot;
}

View File

@@ -77,6 +77,11 @@ public sealed partial class FAT
const ushort EAT_ASN1 = 0xFFDD;
const string FAT32_EA_TAIL = " EA. SF";
const string FS_TYPE_FAT_PLUS = "fatplus";
const string FS_TYPE_FAT32 = "fat32";
const string FS_TYPE_FAT16 = "fat16";
const string FS_TYPE_FAT12 = "fat12";
readonly (string hash, string name)[] _knownBootHashes =
{
("b639b4d5b25f63560e3b34a3a0feb732aa65486f", "Amstrad MS-DOS 3.20 (8-sector floppy)"),
@@ -170,35 +175,31 @@ public sealed partial class FAT
("91e2b47c3cb46611249e4daa283a68ba21ba596a", "Human68k 2.00")
};
[Flags]
enum FatAttributes : byte
{
ReadOnly = 0x01, Hidden = 0x02, System = 0x04,
VolumeLabel = 0x08, Subdirectory = 0x10, Archive = 0x20,
Device = 0x40, Reserved = 0x80, LFN = 0x0F
}
#region Nested type: BpbKind
enum BpbKind
{
None, Hardcoded, Atari,
Msx, Dos2, Dos3,
Dos32, Dos33, ShortExtended,
Extended, ShortFat32, LongFat32,
Andos, Apricot, DecRainbow,
None,
Hardcoded,
Atari,
Msx,
Dos2,
Dos3,
Dos32,
Dos33,
ShortExtended,
Extended,
ShortFat32,
LongFat32,
Andos,
Apricot,
DecRainbow,
Human
}
enum Namespace
{
Dos, Nt, Lfn,
Os2, Ecs, Human
}
#endregion
[Flags]
enum EaFlags : uint
{
Normal = 0, Critical = 1
}
#region Nested type: CaseInfo
[Flags]
enum CaseInfo : byte
@@ -206,7 +207,8 @@ public sealed partial class FAT
/// <summary>FASTFAT.SYS indicator that basename is lowercase</summary>
LowerCaseBasename = 0x08,
/// <summary>FASTFAT.SYS indicator that extension is lowercase</summary>
LowerCaseExtension = 0x10, AllLowerCase = 0x18,
LowerCaseExtension = 0x10,
AllLowerCase = 0x18,
/// <summary>FAT32.IFS &lt; 0.97 indicator for normal EAs present</summary>
NormalEaOld = 0xEA,
/// <summary>FAT32.IFS &lt; 0.97 indicator for critical EAs present</summary>
@@ -217,8 +219,48 @@ public sealed partial class FAT
CriticalEa = 0x80
}
const string FS_TYPE_FAT_PLUS = "fatplus";
const string FS_TYPE_FAT32 = "fat32";
const string FS_TYPE_FAT16 = "fat16";
const string FS_TYPE_FAT12 = "fat12";
#endregion
#region Nested type: EaFlags
[Flags]
enum EaFlags : uint
{
Normal = 0,
Critical = 1
}
#endregion
#region Nested type: FatAttributes
[Flags]
enum FatAttributes : byte
{
ReadOnly = 0x01,
Hidden = 0x02,
System = 0x04,
VolumeLabel = 0x08,
Subdirectory = 0x10,
Archive = 0x20,
Device = 0x40,
Reserved = 0x80,
LFN = 0x0F
}
#endregion
#region Nested type: Namespace
enum Namespace
{
Dos,
Nt,
Lfn,
Os2,
Ecs,
Human
}
#endregion
}

View File

@@ -40,6 +40,8 @@ namespace Aaru.Filesystems;
public sealed partial class FAT
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
/// <summary>Solves a symbolic link.</summary>
/// <param name="path">Link path.</param>
@@ -72,7 +74,8 @@ public sealed partial class FAT
return ErrorNumber.NoError;
}
string cutPath = path.StartsWith("/", StringComparison.Ordinal) ? path[1..].ToLower(_cultureInfo)
string cutPath = path.StartsWith("/", StringComparison.Ordinal)
? path[1..].ToLower(_cultureInfo)
: path.ToLower(_cultureInfo);
if(_directoryCache.TryGetValue(cutPath, out Dictionary<string, CompleteDirectoryEntry> currentDirectory))
@@ -87,10 +90,7 @@ public sealed partial class FAT
return ErrorNumber.NoError;
}
string[] pieces = cutPath.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pieces = cutPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
KeyValuePair<string, CompleteDirectoryEntry> entry =
_rootDirectoryCache.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[0]);
@@ -105,7 +105,7 @@ public sealed partial class FAT
currentDirectory = _rootDirectoryCache;
for(int p = 0; p < pieces.Length; p++)
for(var p = 0; p < pieces.Length; p++)
{
entry = currentDirectory.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[p]);
@@ -144,11 +144,11 @@ public sealed partial class FAT
if(clusters is null)
return ErrorNumber.InvalidArgument;
byte[] directoryBuffer = new byte[_bytesPerCluster * clusters.Length];
var directoryBuffer = new byte[_bytesPerCluster * clusters.Length];
for(int i = 0; i < clusters.Length; i++)
for(var i = 0; i < clusters.Length; i++)
{
ErrorNumber errno = _image.ReadSectors(_firstClusterSector + (clusters[i] * _sectorsPerCluster),
ErrorNumber errno = _image.ReadSectors(_firstClusterSector + clusters[i] * _sectorsPerCluster,
_sectorsPerCluster, out byte[] buffer);
if(errno != ErrorNumber.NoError)
@@ -161,7 +161,7 @@ public sealed partial class FAT
byte[] lastLfnName = null;
byte lastLfnChecksum = 0;
for(int pos = 0; pos < directoryBuffer.Length; pos += Marshal.SizeOf<DirectoryEntry>())
for(var pos = 0; pos < directoryBuffer.Length; pos += Marshal.SizeOf<DirectoryEntry>())
{
DirectoryEntry dirent =
Marshal.ByteArrayToStructureLittleEndian<DirectoryEntry>(directoryBuffer, pos,
@@ -199,9 +199,9 @@ public sealed partial class FAT
lfnSequence--;
Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10);
Array.Copy(lfnEntry.name2, 0, lastLfnName, (lfnSequence * 26) + 10, 12);
Array.Copy(lfnEntry.name3, 0, lastLfnName, (lfnSequence * 26) + 22, 4);
Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10);
Array.Copy(lfnEntry.name2, 0, lastLfnName, lfnSequence * 26 + 10, 12);
Array.Copy(lfnEntry.name3, 0, lastLfnName, lfnSequence * 26 + 22, 4);
continue;
}
@@ -267,7 +267,7 @@ public sealed partial class FAT
name = ":{EMPTYNAME}:";
// Try to create a unique filename with an extension from 000 to 999
for(int uniq = 0; uniq < 1000; uniq++)
for(var uniq = 0; uniq < 1000; uniq++)
{
extension = $"{uniq:D03}";
@@ -302,7 +302,7 @@ public sealed partial class FAT
completeEntry.HumanDirent = humanEntry;
name = StringHandlers.CToString(humanEntry.name1, _encoding).TrimEnd();
name = StringHandlers.CToString(humanEntry.name1, _encoding).TrimEnd();
extension = StringHandlers.CToString(humanEntry.extension, _encoding).TrimEnd();
string name2 = StringHandlers.CToString(humanEntry.name2, _encoding).TrimEnd();
@@ -329,7 +329,7 @@ public sealed partial class FAT
_namespace is Namespace.Os2 or Namespace.Ecs &&
!_fat32)
{
List<KeyValuePair<string, CompleteDirectoryEntry>> filesWithEas =
var filesWithEas =
currentDirectory.Where(t => t.Value.Dirent.ea_handle != 0).ToList();
foreach(KeyValuePair<string, CompleteDirectoryEntry> fileWithEa in filesWithEas)
@@ -345,12 +345,12 @@ public sealed partial class FAT
if(BitConverter.ToUInt16(longnameEa, 0) != EAT_ASCII)
continue;
ushort longnameSize = BitConverter.ToUInt16(longnameEa, 2);
var longnameSize = BitConverter.ToUInt16(longnameEa, 2);
if(longnameSize + 4 > longnameEa.Length)
continue;
byte[] longnameBytes = new byte[longnameSize];
var longnameBytes = new byte[longnameSize];
Array.Copy(longnameEa, 4, longnameBytes, 0, longnameSize);
@@ -371,7 +371,7 @@ public sealed partial class FAT
// Check FAT32.IFS EAs
if(_fat32 || _debug)
{
List<KeyValuePair<string, CompleteDirectoryEntry>> fat32EaSidecars =
var fat32EaSidecars =
currentDirectory.Where(t => t.Key.EndsWith(FAT32_EA_TAIL, true, _cultureInfo)).ToList();
foreach(KeyValuePair<string, CompleteDirectoryEntry> sidecar in fat32EaSidecars)
@@ -383,11 +383,13 @@ public sealed partial class FAT
// If not in debug mode we will consider the lack of EA bitflags to mean the EAs are corrupted or not real
if(!_debug)
{
if(!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.NormalEaOld) &&
!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.CriticalEa) &&
!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.NormalEa) &&
!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.CriticalEa))
continue;
}
fileWithEa.Fat32Ea = sidecar.Value.Dirent;
@@ -432,14 +434,14 @@ public sealed partial class FAT
CompleteDirectoryEntry entry = mynode._entries[mynode._position];
filename = _namespace switch
{
Namespace.Ecs when entry.Longname is not null => entry.Longname,
Namespace.Ecs when entry.Longname is null && entry.Lfn is not null => entry.Lfn,
Namespace.Lfn when entry.Lfn is not null => entry.Lfn,
Namespace.Human when entry.HumanName is not null => entry.HumanName,
Namespace.Os2 when entry.Longname is not null => entry.Longname,
_ => entry.Shortname
};
{
Namespace.Ecs when entry.Longname is not null => entry.Longname,
Namespace.Ecs when entry.Longname is null && entry.Lfn is not null => entry.Lfn,
Namespace.Lfn when entry.Lfn is not null => entry.Lfn,
Namespace.Human when entry.HumanName is not null => entry.HumanName,
Namespace.Os2 when entry.Longname is not null => entry.Longname,
_ => entry.Shortname
};
mynode._position++;
@@ -457,4 +459,6 @@ public sealed partial class FAT
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -42,18 +42,22 @@ namespace Aaru.Filesystems;
/// <summary>Implements the File Allocation Table, aka FAT, filesystem (FAT12, FAT16 and FAT32 variants).</summary>
public sealed partial class FAT : IReadOnlyFilesystem
{
const string MODULE_NAME = "FAT plugin";
uint _bytesPerCluster;
byte[] _cachedEaData;
CultureInfo _cultureInfo;
bool _debug;
Dictionary<string, Dictionary<string, CompleteDirectoryEntry>> _directoryCache;
DirectoryEntry _eaDirEntry;
Encoding _encoding;
bool _fat12;
bool _fat16;
bool _fat32;
ushort[] _fatEntries;
uint _fatEntriesPerSector;
ulong _fatFirstSector;
ulong _firstClusterSector;
IMediaImage _image;
bool _mounted;
Namespace _namespace;
uint _reservedSectors;
@@ -62,16 +66,18 @@ public sealed partial class FAT : IReadOnlyFilesystem
uint _sectorsPerFat;
FileSystemInfo _statfs;
bool _useFirstFat;
Encoding _encoding;
uint _fatEntriesPerSector;
IMediaImage _image;
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public FileSystem Metadata { get; private set; }
/// <inheritdoc />
public string Name => Localization.FAT_Name;
/// <inheritdoc />
public Guid Id => new("33513B2C-0D26-0D2D-32C3-79D8611158E0");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
@@ -82,29 +88,17 @@ public sealed partial class FAT : IReadOnlyFilesystem
/// <inheritdoc />
public Dictionary<string, string> Namespaces => new()
{
{
"dos", Localization.DOS_8_3_all_uppercase
},
{
"nt", Localization.Windows_NT_8_3_mixed_case
},
{
"os2", Localization.OS2_LONGNAME_extended_attribute
},
{
"ecs", Localization.Use_LFN_when_available_with_fallback_to_LONGNAME_default
},
{
"lfn", Localization.Long_file_names
}
{ "dos", Localization.DOS_8_3_all_uppercase },
{ "nt", Localization.Windows_NT_8_3_mixed_case },
{ "os2", Localization.OS2_LONGNAME_extended_attribute },
{ "ecs", Localization.Use_LFN_when_available_with_fallback_to_LONGNAME_default },
{ "lfn", Localization.Long_file_names }
};
#endregion
static Dictionary<string, string> GetDefaultOptions() => new()
{
{
"debug", false.ToString()
}
{ "debug", false.ToString() }
};
const string MODULE_NAME = "FAT plugin";
}

View File

@@ -40,6 +40,8 @@ namespace Aaru.Filesystems;
public sealed partial class FAT
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber GetAttributes(string path, out FileAttributes attributes)
{
@@ -134,13 +136,13 @@ public sealed partial class FAT
var ms = new MemoryStream();
for(int i = 0; i < sizeInClusters; i++)
for(var i = 0; i < sizeInClusters; i++)
{
if(i + firstCluster >= mynode._clusters.Length)
return ErrorNumber.InvalidArgument;
ErrorNumber errno =
_image.ReadSectors(_firstClusterSector + (mynode._clusters[i + firstCluster] * _sectorsPerCluster),
_image.ReadSectors(_firstClusterSector + mynode._clusters[i + firstCluster] * _sectorsPerCluster,
_sectorsPerCluster, out byte[] buf);
if(errno != ErrorNumber.NoError)
@@ -202,10 +204,13 @@ public sealed partial class FAT
{
stat.Attributes |= FileAttributes.Directory;
if((_fat32 && entry.ea_handle << 16 > 0) ||
if(_fat32 && entry.ea_handle << 16 > 0 ||
entry.start_cluster > 0)
stat.Blocks = _fat32 ? GetClusters((uint)((entry.ea_handle << 16) + entry.start_cluster))?.Length ?? 0
: GetClusters(entry.start_cluster)?.Length ?? 0;
{
stat.Blocks = _fat32
? GetClusters((uint)((entry.ea_handle << 16) + entry.start_cluster))?.Length ?? 0
: GetClusters(entry.start_cluster)?.Length ?? 0;
}
stat.Length = stat.Blocks * stat.BlockSize;
}
@@ -228,6 +233,8 @@ public sealed partial class FAT
return ErrorNumber.NoError;
}
#endregion
uint[] GetClusters(uint startCluster)
{
if(startCluster == 0)
@@ -240,9 +247,9 @@ public sealed partial class FAT
uint nextCluster = startCluster;
ulong nextSector = (nextCluster / _fatEntriesPerSector) + _fatFirstSector + (_useFirstFat ? 0 : _sectorsPerFat);
ulong nextSector = nextCluster / _fatEntriesPerSector + _fatFirstSector + (_useFirstFat ? 0 : _sectorsPerFat);
int nextEntry = (int)(nextCluster % _fatEntriesPerSector);
var nextEntry = (int)(nextCluster % _fatEntriesPerSector);
ulong currentSector = nextSector;
ErrorNumber errno = _image.ReadSector(currentSector, out byte[] fatData);
@@ -251,6 +258,7 @@ public sealed partial class FAT
return null;
if(_fat32)
{
while((nextCluster & FAT32_MASK) > 0 &&
(nextCluster & FAT32_MASK) <= FAT32_RESERVED)
{
@@ -268,12 +276,14 @@ public sealed partial class FAT
nextCluster = BitConverter.ToUInt32(fatData, nextEntry * 4);
nextSector = (nextCluster / _fatEntriesPerSector) + _fatFirstSector +
nextSector = nextCluster / _fatEntriesPerSector + _fatFirstSector +
(_useFirstFat ? 0 : _sectorsPerFat);
nextEntry = (int)(nextCluster % _fatEntriesPerSector);
}
}
else if(_fat16)
{
while(nextCluster is > 0 and <= FAT16_RESERVED)
{
if(nextCluster >= _fatEntries.Length)
@@ -282,7 +292,9 @@ public sealed partial class FAT
clusters.Add(nextCluster);
nextCluster = _fatEntries[nextCluster];
}
}
else
{
while(nextCluster is > 0 and <= FAT12_RESERVED)
{
if(nextCluster >= _fatEntries.Length)
@@ -291,6 +303,7 @@ public sealed partial class FAT
clusters.Add(nextCluster);
nextCluster = _fatEntries[nextCluster];
}
}
return clusters.ToArray();
}
@@ -301,15 +314,12 @@ public sealed partial class FAT
string cutPath = path.StartsWith('/') ? path[1..].ToLower(_cultureInfo) : path.ToLower(_cultureInfo);
string[] pieces = cutPath.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pieces = cutPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pieces.Length == 0)
return ErrorNumber.InvalidArgument;
string parentPath = string.Join("/", pieces, 0, pieces.Length - 1);
var parentPath = string.Join("/", pieces, 0, pieces.Length - 1);
if(!_directoryCache.TryGetValue(parentPath, out _))
{
@@ -343,10 +353,10 @@ public sealed partial class FAT
{
byte sum = 0;
for(int i = 0; i < 8; i++)
for(var i = 0; i < 8; i++)
sum = (byte)(((sum & 1) << 7) + (sum >> 1) + name[i]);
for(int i = 0; i < 3; i++)
for(var i = 0; i < 3; i++)
sum = (byte)(((sum & 1) << 7) + (sum >> 1) + extension[i]);
return sum;

View File

@@ -45,6 +45,8 @@ namespace Aaru.Filesystems;
public sealed partial class FAT
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
[SuppressMessage("ReSharper", "JoinDeclarationAndInitializer")]
public bool Identify(IMediaImage imagePlugin, Partition partition)
@@ -64,11 +66,11 @@ public sealed partial class FAT
byte bpbSignature;
byte fat32Signature;
ulong hugeSectors;
byte[] fat32Id = new byte[8];
byte[] msxId = new byte[6];
var fat32Id = new byte[8];
var msxId = new byte[6];
byte fatId;
byte[] dosOem = new byte[8];
byte[] atariOem = new byte[6];
var dosOem = new byte[8];
var atariOem = new byte[6];
ushort bootable = 0;
uint sectorsPerBpb = imagePlugin.Info.SectorSize < 512 ? 512 / imagePlugin.Info.SectorSize : 1;
@@ -87,14 +89,15 @@ public sealed partial class FAT
ulong expectedClusters = humanBpb.bpc > 0 ? partition.Size / humanBpb.bpc : 0;
AaruConsole.DebugWriteLine(MODULE_NAME, "Human bpc = {0}", humanBpb.bpc);
AaruConsole.DebugWriteLine(MODULE_NAME, "Human clusters = {0}", humanBpb.clusters);
AaruConsole.DebugWriteLine(MODULE_NAME, "Human big_clusters = {0}", humanBpb.big_clusters);
AaruConsole.DebugWriteLine(MODULE_NAME, "Human bpc = {0}", humanBpb.bpc);
AaruConsole.DebugWriteLine(MODULE_NAME, "Human clusters = {0}", humanBpb.clusters);
AaruConsole.DebugWriteLine(MODULE_NAME, "Human big_clusters = {0}", humanBpb.big_clusters);
AaruConsole.DebugWriteLine(MODULE_NAME, "Human expected clusters = {0}", expectedClusters);
// Check clusters for Human68k are correct
bool humanClustersCorrect = humanBpb.clusters == 0 ? humanBpb.big_clusters == expectedClusters
: humanBpb.clusters == expectedClusters;
bool humanClustersCorrect = humanBpb.clusters == 0
? humanBpb.big_clusters == expectedClusters
: humanBpb.clusters == expectedClusters;
// Check OEM for Human68k is correct
bool humanOemCorrect = bpbSector[2] >= 0x20 && bpbSector[3] >= 0x20 && bpbSector[4] >= 0x20 &&
@@ -108,8 +111,8 @@ public sealed partial class FAT
bool humanBranchCorrect = bpbSector[0] == 0x60 && bpbSector[1] >= 0x20 && bpbSector[1] < 0xFE;
AaruConsole.DebugWriteLine(MODULE_NAME, "humanClustersCorrect = {0}", humanClustersCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "humanOemCorrect = {0}", humanOemCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "humanBranchCorrect = {0}", humanBranchCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "humanOemCorrect = {0}", humanOemCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "humanBranchCorrect = {0}", humanBranchCorrect);
// If all Human68k checks are correct, it is a Human68k FAT16
if(humanClustersCorrect &&
@@ -119,7 +122,7 @@ public sealed partial class FAT
return true;
Array.Copy(bpbSector, 0x02, atariOem, 0, 6);
Array.Copy(bpbSector, 0x03, dosOem, 0, 8);
Array.Copy(bpbSector, 0x03, dosOem, 0, 8);
bps = BitConverter.ToUInt16(bpbSector, 0x00B);
spc = bpbSector[0x00D];
reservedSecs = BitConverter.ToUInt16(bpbSector, 0x00E);
@@ -152,49 +155,49 @@ public sealed partial class FAT
string oemString = Encoding.ASCII.GetString(dosOem);
AaruConsole.DebugWriteLine(MODULE_NAME, "atari_oem_correct = {0}", atariOemCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "dos_oem_correct = {0}", dosOemCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "bps = {0}", bps);
AaruConsole.DebugWriteLine(MODULE_NAME, "bits in bps = {0}", bitsInBps);
AaruConsole.DebugWriteLine(MODULE_NAME, "spc = {0}", spc);
AaruConsole.DebugWriteLine(MODULE_NAME, "correct_spc = {0}", correctSpc);
AaruConsole.DebugWriteLine(MODULE_NAME, "reserved_secs = {0}", reservedSecs);
AaruConsole.DebugWriteLine(MODULE_NAME, "fats_no = {0}", numberOfFats);
AaruConsole.DebugWriteLine(MODULE_NAME, "root_entries = {0}", rootEntries);
AaruConsole.DebugWriteLine(MODULE_NAME, "sectors = {0}", sectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "atari_oem_correct = {0}", atariOemCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "dos_oem_correct = {0}", dosOemCorrect);
AaruConsole.DebugWriteLine(MODULE_NAME, "bps = {0}", bps);
AaruConsole.DebugWriteLine(MODULE_NAME, "bits in bps = {0}", bitsInBps);
AaruConsole.DebugWriteLine(MODULE_NAME, "spc = {0}", spc);
AaruConsole.DebugWriteLine(MODULE_NAME, "correct_spc = {0}", correctSpc);
AaruConsole.DebugWriteLine(MODULE_NAME, "reserved_secs = {0}", reservedSecs);
AaruConsole.DebugWriteLine(MODULE_NAME, "fats_no = {0}", numberOfFats);
AaruConsole.DebugWriteLine(MODULE_NAME, "root_entries = {0}", rootEntries);
AaruConsole.DebugWriteLine(MODULE_NAME, "sectors = {0}", sectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "media_descriptor = 0x{0:X2}", mediaDescriptor);
AaruConsole.DebugWriteLine(MODULE_NAME, "fat_sectors = {0}", fatSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "msx_id = \"{0}\"", msxString);
AaruConsole.DebugWriteLine(MODULE_NAME, "big_sectors = {0}", bigSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "bpb_signature = 0x{0:X2}", bpbSignature);
AaruConsole.DebugWriteLine(MODULE_NAME, "fat32_signature = 0x{0:X2}", fat32Signature);
AaruConsole.DebugWriteLine(MODULE_NAME, "fat32_id = \"{0}\"", fat32String);
AaruConsole.DebugWriteLine(MODULE_NAME, "huge_sectors = {0}", hugeSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "fat_id = 0x{0:X2}", fatId);
AaruConsole.DebugWriteLine(MODULE_NAME, "fat_sectors = {0}", fatSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "msx_id = \"{0}\"", msxString);
AaruConsole.DebugWriteLine(MODULE_NAME, "big_sectors = {0}", bigSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "bpb_signature = 0x{0:X2}", bpbSignature);
AaruConsole.DebugWriteLine(MODULE_NAME, "fat32_signature = 0x{0:X2}", fat32Signature);
AaruConsole.DebugWriteLine(MODULE_NAME, "fat32_id = \"{0}\"", fat32String);
AaruConsole.DebugWriteLine(MODULE_NAME, "huge_sectors = {0}", hugeSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "fat_id = 0x{0:X2}", fatId);
ushort apricotBps = BitConverter.ToUInt16(bpbSector, 0x50);
byte apricotSpc = bpbSector[0x52];
ushort apricotReservedSecs = BitConverter.ToUInt16(bpbSector, 0x53);
byte apricotFatsNo = bpbSector[0x55];
ushort apricotRootEntries = BitConverter.ToUInt16(bpbSector, 0x56);
ushort apricotSectors = BitConverter.ToUInt16(bpbSector, 0x58);
byte apricotMediaDescriptor = bpbSector[0x5A];
ushort apricotFatSectors = BitConverter.ToUInt16(bpbSector, 0x5B);
var apricotBps = BitConverter.ToUInt16(bpbSector, 0x50);
byte apricotSpc = bpbSector[0x52];
var apricotReservedSecs = BitConverter.ToUInt16(bpbSector, 0x53);
byte apricotFatsNo = bpbSector[0x55];
var apricotRootEntries = BitConverter.ToUInt16(bpbSector, 0x56);
var apricotSectors = BitConverter.ToUInt16(bpbSector, 0x58);
byte apricotMediaDescriptor = bpbSector[0x5A];
var apricotFatSectors = BitConverter.ToUInt16(bpbSector, 0x5B);
bool apricotCorrectSpc = apricotSpc is 1 or 2 or 4 or 8 or 16 or 32 or 64;
int bitsInApricotBps = CountBits.Count(apricotBps);
byte apricotPartitions = bpbSector[0x0C];
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_bps = {0}", apricotBps);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_spc = {0}", apricotSpc);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_correct_spc = {0}", apricotCorrectSpc);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_reserved_secs = {0}", apricotReservedSecs);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_fats_no = {0}", apricotFatsNo);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_root_entries = {0}", apricotRootEntries);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_sectors = {0}", apricotSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_bps = {0}", apricotBps);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_spc = {0}", apricotSpc);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_correct_spc = {0}", apricotCorrectSpc);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_reserved_secs = {0}", apricotReservedSecs);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_fats_no = {0}", apricotFatsNo);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_root_entries = {0}", apricotRootEntries);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_sectors = {0}", apricotSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_media_descriptor = 0x{0:X2}", apricotMediaDescriptor);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_fat_sectors = {0}", apricotFatSectors);
AaruConsole.DebugWriteLine(MODULE_NAME, "apricot_fat_sectors = {0}", apricotFatSectors);
// This is to support FAT partitions on hybrid ISO/USB images
if(imagePlugin.Info.MetadataMediaType == MetadataMediaType.OpticalDisc)
@@ -207,13 +210,16 @@ public sealed partial class FAT
switch(oemString)
{
// exFAT
case "EXFAT ": return false;
case "EXFAT ":
return false;
// NTFS
case "NTFS " when bootable == 0xAA55 && numberOfFats == 0 && fatSectors == 0: return false;
case "NTFS " when bootable == 0xAA55 && numberOfFats == 0 && fatSectors == 0:
return false;
// QNX4
case "FQNX4FS ": return false;
case "FQNX4FS ":
return false;
}
// HPFS
@@ -225,8 +231,8 @@ public sealed partial class FAT
if(errno != ErrorNumber.NoError)
return false;
uint hpfsMagic1 = BitConverter.ToUInt32(hpfsSbSector, 0x000);
uint hpfsMagic2 = BitConverter.ToUInt32(hpfsSbSector, 0x004);
var hpfsMagic1 = BitConverter.ToUInt32(hpfsSbSector, 0x000);
var hpfsMagic2 = BitConverter.ToUInt32(hpfsSbSector, 0x004);
if(hpfsMagic1 == 0xF995E849 &&
hpfsMagic2 == 0xFA53E9C5)
@@ -237,31 +243,36 @@ public sealed partial class FAT
{
// FAT32 for sure
case 1 when correctSpc && numberOfFats <= 2 && fatSectors == 0 && fat32Signature == 0x29 &&
fat32String == "FAT32 ": return true;
fat32String == "FAT32 ":
return true;
// short FAT32
case 1 when correctSpc && numberOfFats <= 2 && fatSectors == 0 && fat32Signature == 0x28:
return sectors == 0 ? bigSectors == 0
? hugeSectors <= partition.End - partition.Start + 1
: bigSectors <= partition.End - partition.Start + 1
return sectors == 0
? bigSectors == 0
? hugeSectors <= partition.End - partition.Start + 1
: bigSectors <= partition.End - partition.Start + 1
: sectors <= partition.End - partition.Start + 1;
// MSX-DOS FAT12
case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 &&
sectors <= partition.End - partition.Start + 1 && fatSectors > 0 &&
msxString == "VOL_ID": return true;
msxString == "VOL_ID":
return true;
// EBPB
case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 && fatSectors > 0 &&
bpbSignature is 0x28 or 0x29:
return sectors == 0 ? bigSectors <= partition.End - partition.Start + 1
: sectors <= partition.End - partition.Start + 1;
return sectors == 0
? bigSectors <= partition.End - partition.Start + 1
: sectors <= partition.End - partition.Start + 1;
// BPB
case 1 when correctSpc && reservedSecs < partition.End - partition.Start && numberOfFats <= 2 &&
rootEntries > 0 && fatSectors > 0:
return sectors == 0 ? bigSectors <= partition.End - partition.Start + 1
: sectors <= partition.End - partition.Start + 1;
return sectors == 0
? bigSectors <= partition.End - partition.Start + 1
: sectors <= partition.End - partition.Start + 1;
}
// Apricot BPB
@@ -302,10 +313,7 @@ public sealed partial class FAT
// Volume is software interleaved 2:1
var rootMs = new MemoryStream();
foreach(ulong rootSector in new ulong[]
{
0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20
})
foreach(ulong rootSector in new ulong[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 })
{
errno = imagePlugin.ReadSector(rootSector, out byte[] tmp);
@@ -316,20 +324,22 @@ public sealed partial class FAT
}
byte[] rootDir = rootMs.ToArray();
bool validRootDir = true;
var validRootDir = true;
// Iterate all root directory
for(int e = 0; e < 96 * 32; e += 32)
for(var e = 0; e < 96 * 32; e += 32)
{
for(int c = 0; c < 11; c++)
if((rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05) ||
rootDir[c + e] == 0xFF ||
for(var c = 0; c < 11; c++)
{
if(rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05 ||
rootDir[c + e] == 0xFF ||
rootDir[c + e] == 0x2E)
{
validRootDir = false;
break;
}
}
if(!validRootDir)
break;
@@ -343,9 +353,9 @@ public sealed partial class FAT
return true;
}
byte fat2 = fatSector[1];
byte fat3 = fatSector[2];
ushort fatCluster2 = (ushort)(((fat2 << 8) + fat3) & 0xFFF);
byte fat2 = fatSector[1];
byte fat3 = fatSector[2];
var fatCluster2 = (ushort)((fat2 << 8) + fat3 & 0xFFF);
AaruConsole.DebugWriteLine(MODULE_NAME, "1st fat cluster 1 = {0:X3}", fatCluster2);
@@ -374,15 +384,15 @@ public sealed partial class FAT
break;
case 0xFE:
fat2SectorNo = imagePlugin.Info.Sectors switch
{
320 when imagePlugin.Info.SectorSize == 512 => 2,
2002 when imagePlugin.Info.SectorSize == 128 => 7,
1232 when imagePlugin.Info.SectorSize == 1024 => 3,
616 when imagePlugin.Info.SectorSize == 1024 => 2,
720 when imagePlugin.Info.SectorSize == 128 => 5,
640 when imagePlugin.Info.SectorSize == 512 => 2,
_ => fat2SectorNo
};
{
320 when imagePlugin.Info.SectorSize == 512 => 2,
2002 when imagePlugin.Info.SectorSize == 128 => 7,
1232 when imagePlugin.Info.SectorSize == 1024 => 3,
616 when imagePlugin.Info.SectorSize == 1024 => 2,
720 when imagePlugin.Info.SectorSize == 128 => 5,
640 when imagePlugin.Info.SectorSize == 512 => 2,
_ => fat2SectorNo
};
break;
case 0xFF:
@@ -412,7 +422,7 @@ public sealed partial class FAT
fat2 = fat2Sector[1];
fat3 = fat2Sector[2];
fatCluster2 = (ushort)(((fat2 << 8) + fat3) & 0xFFF);
fatCluster2 = (ushort)((fat2 << 8) + fat3 & 0xFFF);
if(fatCluster2 < 0xFF0)
return false;
@@ -441,9 +451,9 @@ public sealed partial class FAT
out HumanParameterBlock humanBpb, out AtariParameterBlock atariBpb,
out byte minBootNearJump, out bool andosOemCorrect, out bool bootable);
bool isFat12 = false;
bool isFat16 = false;
bool isFat32 = false;
var isFat12 = false;
var isFat16 = false;
var isFat32 = false;
ulong rootDirectorySector = 0;
string extraInfo = null;
string bootChk = null;
@@ -496,17 +506,19 @@ public sealed partial class FAT
}
if(fat32Bpb.oem_name != null)
{
if(fat32Bpb.oem_name[5] == 0x49 &&
fat32Bpb.oem_name[6] == 0x48 &&
fat32Bpb.oem_name[7] == 0x43)
sb.AppendLine(Localization.Volume_has_been_modified_by_Windows_9x_Me_Volume_Tracker);
else
metadata.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name);
}
if(!string.IsNullOrEmpty(metadata.SystemIdentifier))
sb.AppendFormat(Localization.OEM_name_0, metadata.SystemIdentifier.Trim()).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_sector, fat32Bpb.bps).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_sector, fat32Bpb.bps).AppendLine();
sb.AppendFormat(Localization._0_sectors_per_cluster, fat32Bpb.spc).AppendLine();
metadata.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc);
sb.AppendFormat(Localization._0_sectors_reserved_between_BPB_and_FAT, fat32Bpb.rsectors).AppendLine();
@@ -533,19 +545,19 @@ public sealed partial class FAT
metadata.Clusters = (ulong)(fat32Bpb.sectors / fat32Bpb.spc);
}
sb.AppendFormat(Localization._0_clusters_on_volume, metadata.Clusters).AppendLine();
sb.AppendFormat(Localization.Media_descriptor_0, fat32Bpb.media).AppendLine();
sb.AppendFormat(Localization._0_sectors_per_FAT, fat32Bpb.big_spfat).AppendLine();
sb.AppendFormat(Localization._0_sectors_per_track, fat32Bpb.sptrk).AppendLine();
sb.AppendFormat(Localization._0_heads, fat32Bpb.heads).AppendLine();
sb.AppendFormat(Localization._0_clusters_on_volume, metadata.Clusters).AppendLine();
sb.AppendFormat(Localization.Media_descriptor_0, fat32Bpb.media).AppendLine();
sb.AppendFormat(Localization._0_sectors_per_FAT, fat32Bpb.big_spfat).AppendLine();
sb.AppendFormat(Localization._0_sectors_per_track, fat32Bpb.sptrk).AppendLine();
sb.AppendFormat(Localization._0_heads, fat32Bpb.heads).AppendLine();
sb.AppendFormat(Localization._0_hidden_sectors_before_BPB, fat32Bpb.hsectors).AppendLine();
sb.AppendFormat(Localization.Cluster_of_root_directory_0, fat32Bpb.root_cluster).AppendLine();
sb.AppendFormat(Localization.Cluster_of_root_directory_0, fat32Bpb.root_cluster).AppendLine();
sb.AppendFormat(Localization.Sector_of_FSINFO_structure_0, fat32Bpb.fsinfo_sector).AppendLine();
sb.AppendFormat(Localization.Sector_of_backup_FAT32_parameter_block_0, fat32Bpb.backup_sector).
AppendLine();
sb.AppendFormat(Localization.Drive_number_0, fat32Bpb.drive_no).AppendLine();
sb.AppendFormat(Localization.Drive_number_0, fat32Bpb.drive_no).AppendLine();
sb.AppendFormat(Localization.Volume_Serial_Number_0, fat32Bpb.serial_no).AppendLine();
metadata.VolumeSerial = $"{fat32Bpb.serial_no:X8}";
@@ -562,8 +574,10 @@ public sealed partial class FAT
}
if((fat32Bpb.mirror_flags & 0x80) == 0x80)
{
sb.AppendFormat(Localization.FATs_are_out_of_sync_FAT_0_is_in_use, fat32Bpb.mirror_flags & 0xF).
AppendLine();
}
else
sb.AppendLine(Localization.All_copies_of_FAT_are_the_same);
@@ -588,16 +602,16 @@ public sealed partial class FAT
// Check that jumps to a correct boot code position and has boot signature set.
// This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
metadata.Bootable =
(fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80) ||
(fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 &&
BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump &&
BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC);
fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80 ||
fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 &&
BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump &&
BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC;
sectorsPerRealSector = fat32Bpb.bps / imagePlugin.Info.SectorSize;
// First root directory sector
rootDirectorySector =
(ulong)(((fat32Bpb.root_cluster - 2) * fat32Bpb.spc) + (fat32Bpb.big_spfat * fat32Bpb.fats_no) +
(ulong)((fat32Bpb.root_cluster - 2) * fat32Bpb.spc + fat32Bpb.big_spfat * fat32Bpb.fats_no +
fat32Bpb.rsectors) * sectorsPerRealSector;
sectorsForRootDirectory = 1;
@@ -633,7 +647,7 @@ public sealed partial class FAT
{
ushort sum = 0;
for(int i = 0; i < bpbSector.Length; i += 2)
for(var i = 0; i < bpbSector.Length; i += 2)
sum += BigEndianBitConverter.ToUInt16(bpbSector, i);
// TODO: Check this
@@ -653,7 +667,7 @@ public sealed partial class FAT
if(atariBpb.ldmode == 0)
{
byte[] tmp = new byte[8];
var tmp = new byte[8];
Array.Copy(atariBpb.fname, 0, tmp, 0, 8);
string fname = Encoding.ASCII.GetString(tmp).Trim();
tmp = new byte[3];
@@ -669,9 +683,11 @@ public sealed partial class FAT
atariSb.AppendFormat(Localization.Boot_program_resides_in_file_0, filename).AppendLine();
}
else
{
atariSb.AppendFormat(Localization.Boot_program_starts_in_sector_0_and_is_1_sectors_long_2_bytes,
atariBpb.ssect, atariBpb.sectcnt, atariBpb.sectcnt * atariBpb.bps).
AppendLine();
}
extraInfo = atariSb.ToString();
}
@@ -705,15 +721,21 @@ public sealed partial class FAT
if(bpbKind != BpbKind.Human)
{
int reservedSectors = fakeBpb.rsectors + (fakeBpb.fats_no * fakeBpb.spfat) +
(fakeBpb.root_ent * 32 / fakeBpb.bps);
int reservedSectors = fakeBpb.rsectors + fakeBpb.fats_no * fakeBpb.spfat +
fakeBpb.root_ent * 32 / fakeBpb.bps;
if(fakeBpb.sectors == 0)
clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.big_sectors - reservedSectors
{
clusters = (ulong)(fakeBpb.spc == 0
? fakeBpb.big_sectors - reservedSectors
: (fakeBpb.big_sectors - reservedSectors) / fakeBpb.spc);
}
else
clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors - reservedSectors
{
clusters = (ulong)(fakeBpb.spc == 0
? fakeBpb.sectors - reservedSectors
: (fakeBpb.sectors - reservedSectors) / fakeBpb.spc);
}
}
else
clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters;
@@ -727,20 +749,20 @@ public sealed partial class FAT
if(clusters < 4089)
{
// The first 2 FAT entries do not count as allocation clusters in FAT12 and FAT16
ushort[] fat12 = new ushort[clusters + 2];
var fat12 = new ushort[clusters + 2];
_reservedSectors = fakeBpb.rsectors;
sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize;
_fatFirstSector = partition.Start + (_reservedSectors * sectorsPerRealSector);
_fatFirstSector = partition.Start + _reservedSectors * sectorsPerRealSector;
errno = imagePlugin.ReadSectors(_fatFirstSector, fakeBpb.spfat, out byte[] fatBytes);
if(errno != ErrorNumber.NoError)
return;
int pos = 0;
var pos = 0;
for(int i = 0; i + 3 < fatBytes.Length && pos < fat12.Length; i += 3)
for(var i = 0; i + 3 < fatBytes.Length && pos < fat12.Length; i += 3)
{
fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]);
@@ -808,11 +830,11 @@ public sealed partial class FAT
else if(isFat16)
{
sb.AppendLine(bpbKind switch
{
BpbKind.Atari => Localization.Atari_FAT16,
BpbKind.Human => Localization.Human68k_FAT16,
_ => Localization.Microsoft_FAT16
});
{
BpbKind.Atari => Localization.Atari_FAT16,
BpbKind.Human => Localization.Human68k_FAT16,
_ => Localization.Microsoft_FAT16
});
metadata.Type = FS_TYPE_FAT16;
}
@@ -824,8 +846,10 @@ public sealed partial class FAT
atariBpb.serial_no[2] == 0x43)
sb.AppendLine(Localization.Volume_has_been_modified_by_Windows_9x_Me_Volume_Tracker);
else
{
metadata.VolumeSerial = $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2]
:X2}";
}
metadata.SystemIdentifier = StringHandlers.CToString(atariBpb.oem_name);
@@ -839,30 +863,45 @@ public sealed partial class FAT
fakeBpb.oem_name[7] == 0x43)
sb.AppendLine(Localization.Volume_has_been_modified_by_Windows_9x_Me_Volume_Tracker);
else
{
metadata.SystemIdentifier = fakeBpb.oem_name[0] switch
{
// Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies
// OEM ID should be ASCII, otherwise ignore it
>= 0x20 and <= 0x7F when fakeBpb.oem_name[1] >= 0x20 && fakeBpb.oem_name[1] <= 0x7F &&
fakeBpb.oem_name[2] >= 0x20 && fakeBpb.oem_name[2] <= 0x7F &&
fakeBpb.oem_name[3] >= 0x20 && fakeBpb.oem_name[3] <= 0x7F &&
fakeBpb.oem_name[4] >= 0x20 && fakeBpb.oem_name[4] <= 0x7F &&
fakeBpb.oem_name[5] >= 0x20 && fakeBpb.oem_name[5] <= 0x7F &&
fakeBpb.oem_name[6] >= 0x20 && fakeBpb.oem_name[6] <= 0x7F &&
fakeBpb.oem_name[7] >= 0x20 &&
fakeBpb.oem_name[7] <= 0x7F =>
StringHandlers.CToString(fakeBpb.oem_name),
< 0x20 when fakeBpb.oem_name[1] >= 0x20 && fakeBpb.oem_name[1] <= 0x7F &&
fakeBpb.oem_name[2] >= 0x20 && fakeBpb.oem_name[2] <= 0x7F &&
fakeBpb.oem_name[3] >= 0x20 && fakeBpb.oem_name[3] <= 0x7F &&
fakeBpb.oem_name[4] >= 0x20 && fakeBpb.oem_name[4] <= 0x7F &&
fakeBpb.oem_name[5] >= 0x20 && fakeBpb.oem_name[5] <= 0x7F &&
fakeBpb.oem_name[6] >= 0x20 && fakeBpb.oem_name[6] <= 0x7F &&
fakeBpb.oem_name[7] >= 0x20 &&
fakeBpb.oem_name[7] <= 0x7F => StringHandlers.CToString(fakeBpb.oem_name, encoding,
start: 1),
_ => metadata.SystemIdentifier
};
{
// Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies
// OEM ID should be ASCII, otherwise ignore it
>= 0x20 and <= 0x7F when fakeBpb.oem_name[1] >= 0x20 &&
fakeBpb.oem_name[1] <= 0x7F &&
fakeBpb.oem_name[2] >= 0x20 &&
fakeBpb.oem_name[2] <= 0x7F &&
fakeBpb.oem_name[3] >= 0x20 &&
fakeBpb.oem_name[3] <= 0x7F &&
fakeBpb.oem_name[4] >= 0x20 &&
fakeBpb.oem_name[4] <= 0x7F &&
fakeBpb.oem_name[5] >= 0x20 &&
fakeBpb.oem_name[5] <= 0x7F &&
fakeBpb.oem_name[6] >= 0x20 &&
fakeBpb.oem_name[6] <= 0x7F &&
fakeBpb.oem_name[7] >= 0x20 &&
fakeBpb.oem_name[7] <= 0x7F =>
StringHandlers.CToString(fakeBpb.oem_name),
< 0x20 when fakeBpb.oem_name[1] >= 0x20 &&
fakeBpb.oem_name[1] <= 0x7F &&
fakeBpb.oem_name[2] >= 0x20 &&
fakeBpb.oem_name[2] <= 0x7F &&
fakeBpb.oem_name[3] >= 0x20 &&
fakeBpb.oem_name[3] <= 0x7F &&
fakeBpb.oem_name[4] >= 0x20 &&
fakeBpb.oem_name[4] <= 0x7F &&
fakeBpb.oem_name[5] >= 0x20 &&
fakeBpb.oem_name[5] <= 0x7F &&
fakeBpb.oem_name[6] >= 0x20 &&
fakeBpb.oem_name[6] <= 0x7F &&
fakeBpb.oem_name[7] >= 0x20 &&
fakeBpb.oem_name[7] <= 0x7F => StringHandlers.CToString(
fakeBpb.oem_name, encoding,
start: 1),
_ => metadata.SystemIdentifier
};
}
if(fakeBpb.signature is 0x28 or 0x29)
metadata.VolumeSerial = $"{fakeBpb.serial_no:X8}";
@@ -874,24 +913,32 @@ public sealed partial class FAT
sb.AppendFormat(Localization._0_bytes_per_sector, fakeBpb.bps).AppendLine();
if(bpbKind != BpbKind.Human)
{
if(fakeBpb.sectors == 0)
{
sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, fakeBpb.big_sectors,
fakeBpb.big_sectors * fakeBpb.bps).AppendLine();
}
else
{
sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes, fakeBpb.sectors,
fakeBpb.sectors * fakeBpb.bps).AppendLine();
}
}
else
{
sb.AppendFormat(Localization._0_sectors_on_volume_1_bytes,
clusters * humanBpb.bpc / imagePlugin.Info.SectorSize, clusters * humanBpb.bpc).
AppendLine();
}
metadata.Clusters = clusters;
sb.AppendFormat(Localization._0_sectors_per_cluster, fakeBpb.spc).AppendLine();
sb.AppendFormat(Localization._0_clusters_on_volume, metadata.Clusters).AppendLine();
sb.AppendFormat(Localization._0_clusters_on_volume, metadata.Clusters).AppendLine();
metadata.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc);
sb.AppendFormat(Localization._0_sectors_reserved_between_BPB_and_FAT, fakeBpb.rsectors).AppendLine();
sb.AppendFormat(Localization._0_FATs, fakeBpb.fats_no).AppendLine();
sb.AppendFormat(Localization._0_entries_in_root_directory, fakeBpb.root_ent).AppendLine();
sb.AppendFormat(Localization._0_FATs, fakeBpb.fats_no).AppendLine();
sb.AppendFormat(Localization._0_entries_in_root_directory, fakeBpb.root_ent).AppendLine();
if(fakeBpb.media > 0)
sb.AppendFormat(Localization.Media_descriptor_0, fakeBpb.media).AppendLine();
@@ -902,7 +949,7 @@ public sealed partial class FAT
fakeBpb.heads is > 0 and < 256)
{
sb.AppendFormat(Localization._0_sectors_per_track, fakeBpb.sptrk).AppendLine();
sb.AppendFormat(Localization._0_heads, fakeBpb.heads).AppendLine();
sb.AppendFormat(Localization._0_heads, fakeBpb.heads).AppendLine();
}
if(fakeBpb.hsectors <= partition.Start)
@@ -950,16 +997,18 @@ public sealed partial class FAT
// This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
if(metadata.Bootable == false &&
fakeBpb.jump != null)
{
metadata.Bootable |=
(fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80) ||
(fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 &&
BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump &&
BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC);
fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80 ||
fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 &&
BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump &&
BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC;
}
sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize;
// First root directory sector
rootDirectorySector = (ulong)((fakeBpb.spfat * fakeBpb.fats_no) + fakeBpb.rsectors) * sectorsPerRealSector;
rootDirectorySector = (ulong)(fakeBpb.spfat * fakeBpb.fats_no + fakeBpb.rsectors) * sectorsPerRealSector;
sectorsForRootDirectory = (uint)(fakeBpb.root_ent * 32 / imagePlugin.Info.SectorSize);
}
@@ -980,10 +1029,7 @@ public sealed partial class FAT
{
var rootMs = new MemoryStream();
foreach(ulong rootSector in new ulong[]
{
0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20
})
foreach(ulong rootSector in new ulong[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 })
{
errno = imagePlugin.ReadSector(rootSector, out byte[] tmp);
@@ -996,7 +1042,7 @@ public sealed partial class FAT
rootDirectory = rootMs.ToArray();
}
for(int i = 0; i < rootDirectory.Length; i += 32)
for(var i = 0; i < rootDirectory.Length; i += 32)
{
// Not a correct entry
if(rootDirectory[i] < DIRENT_MIN &&
@@ -1015,8 +1061,8 @@ public sealed partial class FAT
DirectoryEntry entry = Marshal.ByteArrayToStructureLittleEndian<DirectoryEntry>(rootDirectory, i, 32);
byte[] fullname = new byte[11];
Array.Copy(entry.filename, 0, fullname, 0, 8);
var fullname = new byte[11];
Array.Copy(entry.filename, 0, fullname, 0, 8);
Array.Copy(entry.extension, 0, fullname, 8, 3);
string volname = encoding.GetString(fullname).Trim();
@@ -1040,8 +1086,10 @@ public sealed partial class FAT
}
if(entry.adate > 0)
{
sb.AppendFormat(Localization.Volume_last_accessed_on_0_d,
DateHandlers.DosToDateTime(entry.adate, 0)).AppendLine();
}
break;
}
@@ -1057,8 +1105,8 @@ public sealed partial class FAT
// Intel short jump
case 0xEB when bpbSector[1] < 0x80:
{
int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0;
byte[] bootCode = new byte[512 - sigSize - bpbSector[1] - 2];
int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0;
var bootCode = new byte[512 - sigSize - bpbSector[1] - 2];
Array.Copy(bpbSector, bpbSector[1] + 2, bootCode, 0, bootCode.Length);
Sha1Context.Data(bootCode, out _);
@@ -1068,8 +1116,8 @@ public sealed partial class FAT
// Intel big jump
case 0xE9 when BitConverter.ToUInt16(bpbSector, 1) < 0x1FC:
{
int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0;
byte[] bootCode = new byte[512 - sigSize - BitConverter.ToUInt16(bpbSector, 1) - 3];
int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0;
var bootCode = new byte[512 - sigSize - BitConverter.ToUInt16(bpbSector, 1) - 3];
Array.Copy(bpbSector, BitConverter.ToUInt16(bpbSector, 1) + 3, bootCode, 0, bootCode.Length);
Sha1Context.Data(bootCode, out _);
@@ -1089,4 +1137,6 @@ public sealed partial class FAT
information = sb.ToString();
}
#endregion
}

File diff suppressed because it is too large Load Diff

View File

@@ -47,9 +47,11 @@ namespace Aaru.Filesystems;
public sealed partial class FAT
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
{
Metadata = new FileSystem();
@@ -87,7 +89,8 @@ public sealed partial class FAT
_namespace = Namespace.Human;
break;
default: return ErrorNumber.InvalidArgument;
default:
return ErrorNumber.InvalidArgument;
}
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_BPB);
@@ -125,7 +128,8 @@ public sealed partial class FAT
uint sectorsForRootDirectory = 0;
uint rootDirectoryCluster = 0;
_encoding = encoding ?? (bpbKind == BpbKind.Human ? Encoding.GetEncoding("shift_jis")
_encoding = encoding ?? (bpbKind == BpbKind.Human
? Encoding.GetEncoding("shift_jis")
: Encoding.GetEncoding("IBM437"));
switch(bpbKind)
@@ -186,8 +190,10 @@ public sealed partial class FAT
};
if((fat32Bpb.flags & 0xF8) == 0x00)
{
if((fat32Bpb.flags & 0x01) == 0x01)
Metadata.Dirty = true;
}
if((fat32Bpb.mirror_flags & 0x80) == 0x80)
_useFirstFat = (fat32Bpb.mirror_flags & 0xF) != 1;
@@ -201,18 +207,18 @@ public sealed partial class FAT
// Check that jumps to a correct boot code position and has boot signature set.
// This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
Metadata.Bootable =
(fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80) ||
(fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 &&
BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump &&
BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC);
fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80 ||
fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 &&
BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump &&
BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC;
sectorsPerRealSector = fat32Bpb.bps / imagePlugin.Info.SectorSize;
_sectorsPerCluster *= sectorsPerRealSector;
// First root directory sector
_firstClusterSector =
((ulong)((fat32Bpb.big_spfat * fat32Bpb.fats_no) + fat32Bpb.rsectors) * sectorsPerRealSector) -
(2 * _sectorsPerCluster);
(ulong)(fat32Bpb.big_spfat * fat32Bpb.fats_no + fat32Bpb.rsectors) * sectorsPerRealSector -
2 * _sectorsPerCluster;
if(fat32Bpb.fsinfo_sector + partition.Start <= partition.End)
{
@@ -224,10 +230,8 @@ public sealed partial class FAT
FsInfoSector fsInfo = Marshal.ByteArrayToStructureLittleEndian<FsInfoSector>(fsinfoSector);
if(fsInfo is { signature1: FSINFO_SIGNATURE1, signature2 : FSINFO_SIGNATURE2 }
and { signature3 : FSINFO_SIGNATURE3, free_clusters: < 0xFFFFFFFF })
{
and { signature3: FSINFO_SIGNATURE3, free_clusters: < 0xFFFFFFFF })
Metadata.FreeClusters = fsInfo.free_clusters;
}
}
break;
@@ -238,7 +242,7 @@ public sealed partial class FAT
{
ushort sum = 0;
for(int i = 0; i < bpbSector.Length; i += 2)
for(var i = 0; i < bpbSector.Length; i += 2)
sum += BigEndianBitConverter.ToUInt16(bpbSector, i);
// TODO: Check this
@@ -290,15 +294,21 @@ public sealed partial class FAT
if(bpbKind != BpbKind.Human)
{
int reservedSectors = fakeBpb.rsectors + (fakeBpb.fats_no * fakeBpb.spfat) +
(fakeBpb.root_ent * 32 / fakeBpb.bps);
int reservedSectors = fakeBpb.rsectors + fakeBpb.fats_no * fakeBpb.spfat +
fakeBpb.root_ent * 32 / fakeBpb.bps;
if(fakeBpb.sectors == 0)
clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.big_sectors - reservedSectors
{
clusters = (ulong)(fakeBpb.spc == 0
? fakeBpb.big_sectors - reservedSectors
: (fakeBpb.big_sectors - reservedSectors) / fakeBpb.spc);
}
else
clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors - reservedSectors
{
clusters = (ulong)(fakeBpb.spc == 0
? fakeBpb.sectors - reservedSectors
: (fakeBpb.sectors - reservedSectors) / fakeBpb.spc);
}
}
else
clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters;
@@ -311,20 +321,20 @@ public sealed partial class FAT
{
if(clusters < 4089)
{
ushort[] fat12 = new ushort[clusters + 1];
var fat12 = new ushort[clusters + 1];
_reservedSectors = fakeBpb.rsectors;
sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize;
_fatFirstSector = partition.Start + (_reservedSectors * sectorsPerRealSector);
_fatFirstSector = partition.Start + _reservedSectors * sectorsPerRealSector;
errno = imagePlugin.ReadSectors(_fatFirstSector, fakeBpb.spfat, out byte[] fatBytes);
if(errno != ErrorNumber.NoError)
return errno;
int pos = 0;
var pos = 0;
for(int i = 0; i + 3 < fatBytes.Length && pos < fat12.Length; i += 3)
for(var i = 0; i + 3 < fatBytes.Length && pos < fat12.Length; i += 3)
{
fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]);
@@ -400,30 +410,45 @@ public sealed partial class FAT
if(fakeBpb.oem_name[5] != 0x49 ||
fakeBpb.oem_name[6] != 0x48 ||
fakeBpb.oem_name[7] != 0x43)
{
Metadata.SystemIdentifier = fakeBpb.oem_name[0] switch
{
// Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies
// OEM ID should be ASCII, otherwise ignore it
>= 0x20 and <= 0x7F when fakeBpb.oem_name[1] >= 0x20 && fakeBpb.oem_name[1] <= 0x7F &&
fakeBpb.oem_name[2] >= 0x20 && fakeBpb.oem_name[2] <= 0x7F &&
fakeBpb.oem_name[3] >= 0x20 && fakeBpb.oem_name[3] <= 0x7F &&
fakeBpb.oem_name[4] >= 0x20 && fakeBpb.oem_name[4] <= 0x7F &&
fakeBpb.oem_name[5] >= 0x20 && fakeBpb.oem_name[5] <= 0x7F &&
fakeBpb.oem_name[6] >= 0x20 && fakeBpb.oem_name[6] <= 0x7F &&
fakeBpb.oem_name[7] >= 0x20 &&
fakeBpb.oem_name[7] <= 0x7F =>
StringHandlers.CToString(fakeBpb.oem_name),
< 0x20 when fakeBpb.oem_name[1] >= 0x20 && fakeBpb.oem_name[1] <= 0x7F &&
fakeBpb.oem_name[2] >= 0x20 && fakeBpb.oem_name[2] <= 0x7F &&
fakeBpb.oem_name[3] >= 0x20 && fakeBpb.oem_name[3] <= 0x7F &&
fakeBpb.oem_name[4] >= 0x20 && fakeBpb.oem_name[4] <= 0x7F &&
fakeBpb.oem_name[5] >= 0x20 && fakeBpb.oem_name[5] <= 0x7F &&
fakeBpb.oem_name[6] >= 0x20 && fakeBpb.oem_name[6] <= 0x7F &&
fakeBpb.oem_name[7] >= 0x20 &&
fakeBpb.oem_name[7] <= 0x7F => StringHandlers.CToString(fakeBpb.oem_name, _encoding,
start: 1),
_ => Metadata.SystemIdentifier
};
{
// Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies
// OEM ID should be ASCII, otherwise ignore it
>= 0x20 and <= 0x7F when fakeBpb.oem_name[1] >= 0x20 &&
fakeBpb.oem_name[1] <= 0x7F &&
fakeBpb.oem_name[2] >= 0x20 &&
fakeBpb.oem_name[2] <= 0x7F &&
fakeBpb.oem_name[3] >= 0x20 &&
fakeBpb.oem_name[3] <= 0x7F &&
fakeBpb.oem_name[4] >= 0x20 &&
fakeBpb.oem_name[4] <= 0x7F &&
fakeBpb.oem_name[5] >= 0x20 &&
fakeBpb.oem_name[5] <= 0x7F &&
fakeBpb.oem_name[6] >= 0x20 &&
fakeBpb.oem_name[6] <= 0x7F &&
fakeBpb.oem_name[7] >= 0x20 &&
fakeBpb.oem_name[7] <= 0x7F =>
StringHandlers.CToString(fakeBpb.oem_name),
< 0x20 when fakeBpb.oem_name[1] >= 0x20 &&
fakeBpb.oem_name[1] <= 0x7F &&
fakeBpb.oem_name[2] >= 0x20 &&
fakeBpb.oem_name[2] <= 0x7F &&
fakeBpb.oem_name[3] >= 0x20 &&
fakeBpb.oem_name[3] <= 0x7F &&
fakeBpb.oem_name[4] >= 0x20 &&
fakeBpb.oem_name[4] <= 0x7F &&
fakeBpb.oem_name[5] >= 0x20 &&
fakeBpb.oem_name[5] <= 0x7F &&
fakeBpb.oem_name[6] >= 0x20 &&
fakeBpb.oem_name[6] <= 0x7F &&
fakeBpb.oem_name[7] >= 0x20 &&
fakeBpb.oem_name[7] <= 0x7F => StringHandlers.CToString(
fakeBpb.oem_name, _encoding,
start: 1),
_ => Metadata.SystemIdentifier
};
}
if(fakeBpb.signature is 0x28 or 0x29)
{
@@ -446,8 +471,10 @@ public sealed partial class FAT
if(fakeBpb.signature is 0x28 or 0x29 || andosOemCorrect)
{
if((fakeBpb.flags & 0xF8) == 0x00)
{
if((fakeBpb.flags & 0x01) == 0x01)
Metadata.Dirty = true;
}
if(fakeBpb.signature == 0x29 || andosOemCorrect)
{
@@ -464,14 +491,16 @@ public sealed partial class FAT
// This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
if(Metadata.Bootable == false &&
fakeBpb.jump != null)
{
Metadata.Bootable |=
(fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80) ||
(fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 &&
BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump &&
BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC);
fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80 ||
fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 &&
BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump &&
BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC;
}
// First root directory sector
firstRootSector = ((ulong)((fakeBpb.spfat * fakeBpb.fats_no) + fakeBpb.rsectors) * sectorsPerRealSector) +
firstRootSector = (ulong)(fakeBpb.spfat * fakeBpb.fats_no + fakeBpb.rsectors) * sectorsPerRealSector +
partition.Start;
sectorsForRootDirectory = (uint)(fakeBpb.root_ent * 32 / imagePlugin.Info.SectorSize);
@@ -491,14 +520,14 @@ public sealed partial class FAT
else
_fatEntriesPerSector = imagePlugin.Info.SectorSize * 2 / 3;
_fatFirstSector = partition.Start + (_reservedSectors * sectorsPerRealSector);
_fatFirstSector = partition.Start + _reservedSectors * sectorsPerRealSector;
_rootDirectoryCache = new Dictionary<string, CompleteDirectoryEntry>();
byte[] rootDirectory;
if(!_fat32)
{
_firstClusterSector = firstRootSector + sectorsForRootDirectory - (_sectorsPerCluster * 2);
_firstClusterSector = firstRootSector + sectorsForRootDirectory - _sectorsPerCluster * 2;
errno = imagePlugin.ReadSectors(firstRootSector, sectorsForRootDirectory, out rootDirectory);
if(errno != ErrorNumber.NoError)
@@ -508,10 +537,7 @@ public sealed partial class FAT
{
var rootMs = new MemoryStream();
foreach(ulong rootSector in new ulong[]
{
0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20
})
foreach(ulong rootSector in new ulong[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 })
{
errno = imagePlugin.ReadSector(rootSector, out byte[] tmp);
@@ -534,7 +560,7 @@ public sealed partial class FAT
foreach(uint cluster in rootDirectoryClusters)
{
errno = imagePlugin.ReadSectors(_firstClusterSector + (cluster * _sectorsPerCluster),
errno = imagePlugin.ReadSectors(_firstClusterSector + cluster * _sectorsPerCluster,
_sectorsPerCluster, out byte[] buffer);
if(errno != ErrorNumber.NoError)
@@ -556,7 +582,7 @@ public sealed partial class FAT
byte[] lastLfnName = null;
byte lastLfnChecksum = 0;
for(int i = 0; i < rootDirectory.Length; i += Marshal.SizeOf<DirectoryEntry>())
for(var i = 0; i < rootDirectory.Length; i += Marshal.SizeOf<DirectoryEntry>())
{
DirectoryEntry entry =
Marshal.ByteArrayToStructureLittleEndian<DirectoryEntry>(rootDirectory, i,
@@ -593,9 +619,9 @@ public sealed partial class FAT
lfnSequence--;
Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10);
Array.Copy(lfnEntry.name2, 0, lastLfnName, (lfnSequence * 26) + 10, 12);
Array.Copy(lfnEntry.name3, 0, lastLfnName, (lfnSequence * 26) + 22, 4);
Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10);
Array.Copy(lfnEntry.name2, 0, lastLfnName, lfnSequence * 26 + 10, 12);
Array.Copy(lfnEntry.name3, 0, lastLfnName, lfnSequence * 26 + 22, 4);
continue;
}
@@ -621,14 +647,17 @@ public sealed partial class FAT
if(entry.attributes.HasFlag(FatAttributes.VolumeLabel))
{
byte[] fullname = new byte[11];
Array.Copy(entry.filename, 0, fullname, 0, 8);
var fullname = new byte[11];
Array.Copy(entry.filename, 0, fullname, 0, 8);
Array.Copy(entry.extension, 0, fullname, 8, 3);
string volname = _encoding.GetString(fullname).Trim();
if(!string.IsNullOrEmpty(volname))
{
Metadata.VolumeName = entry.caseinfo.HasFlag(CaseInfo.AllLowerCase) && _namespace == Namespace.Nt
? volname.ToLower() : volname;
? volname.ToLower()
: volname;
}
Metadata.VolumeName = Metadata.VolumeName?.Replace("\0", "");
@@ -641,9 +670,7 @@ public sealed partial class FAT
}
if(entry is { mtime: > 0, mdate: > 0 })
{
Metadata.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime);
}
continue;
}
@@ -701,7 +728,7 @@ public sealed partial class FAT
name = ":{EMPTYNAME}:";
// Try to create a unique filename with an extension from 000 to 999
for(int uniq = 0; uniq < 1000; uniq++)
for(var uniq = 0; uniq < 1000; uniq++)
{
extension = $"{uniq:D03}";
@@ -727,7 +754,7 @@ public sealed partial class FAT
completeEntry.HumanDirent = humanEntry;
name = StringHandlers.CToString(humanEntry.name1, _encoding).TrimEnd();
name = StringHandlers.CToString(humanEntry.name1, _encoding).TrimEnd();
extension = StringHandlers.CToString(humanEntry.extension, _encoding).TrimEnd();
string name2 = StringHandlers.CToString(humanEntry.name2, _encoding).TrimEnd();
@@ -776,10 +803,10 @@ public sealed partial class FAT
_bytesPerCluster = _sectorsPerCluster * imagePlugin.Info.SectorSize;
// The first 2 FAT entries do not count as allocation clusters in FAT12 and FAT16
ushort[] firstFatEntries = new ushort[_statfs.Blocks + 2];
ushort[] secondFatEntries = new ushort[_statfs.Blocks + 2];
bool firstFatValid = true;
bool secondFatValid = true;
var firstFatEntries = new ushort[_statfs.Blocks + 2];
var secondFatEntries = new ushort[_statfs.Blocks + 2];
var firstFatValid = true;
var secondFatValid = true;
if(_fat12)
{
@@ -790,9 +817,9 @@ public sealed partial class FAT
if(errno != ErrorNumber.NoError)
return errno;
int pos = 0;
var pos = 0;
for(int i = 0; i + 3 < fatBytes.Length && pos < firstFatEntries.Length; i += 3)
for(var i = 0; i + 3 < fatBytes.Length && pos < firstFatEntries.Length; i += 3)
{
firstFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]);
@@ -811,7 +838,7 @@ public sealed partial class FAT
pos = 0;
for(int i = 0; i + 3 < fatBytes.Length && pos < secondFatEntries.Length; i += 3)
for(var i = 0; i + 3 < fatBytes.Length && pos < secondFatEntries.Length; i += 3)
{
secondFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]);
@@ -876,7 +903,7 @@ public sealed partial class FAT
if(_eaDirEntry.start_cluster != 0)
{
CacheEaData();
ushort eamagic = BitConverter.ToUInt16(_cachedEaData, 0);
var eamagic = BitConverter.ToUInt16(_cachedEaData, 0);
if(eamagic != EADATA_MAGIC)
{
@@ -894,7 +921,7 @@ public sealed partial class FAT
_namespace is Namespace.Os2 or Namespace.Ecs &&
!_fat32)
{
List<KeyValuePair<string, CompleteDirectoryEntry>> rootFilesWithEas =
var rootFilesWithEas =
_rootDirectoryCache.Where(t => t.Value.Dirent.ea_handle != 0).ToList();
foreach(KeyValuePair<string, CompleteDirectoryEntry> fileWithEa in rootFilesWithEas)
@@ -910,12 +937,12 @@ public sealed partial class FAT
if(BitConverter.ToUInt16(longnameEa, 0) != EAT_ASCII)
continue;
ushort longnameSize = BitConverter.ToUInt16(longnameEa, 2);
var longnameSize = BitConverter.ToUInt16(longnameEa, 2);
if(longnameSize + 4 > longnameEa.Length)
continue;
byte[] longnameBytes = new byte[longnameSize];
var longnameBytes = new byte[longnameSize];
Array.Copy(longnameEa, 4, longnameBytes, 0, longnameSize);
@@ -936,7 +963,7 @@ public sealed partial class FAT
// Check FAT32.IFS EAs
if(_fat32 || _debug)
{
List<KeyValuePair<string, CompleteDirectoryEntry>> fat32EaSidecars =
var fat32EaSidecars =
_rootDirectoryCache.Where(t => t.Key.EndsWith(FAT32_EA_TAIL, true, _cultureInfo)).ToList();
foreach(KeyValuePair<string, CompleteDirectoryEntry> sidecar in fat32EaSidecars)
@@ -948,11 +975,13 @@ public sealed partial class FAT
// If not in debug mode we will consider the lack of EA bitflags to mean the EAs are corrupted or not real
if(!_debug)
{
if(!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.NormalEaOld) &&
!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.CriticalEa) &&
!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.NormalEa) &&
!fileWithEa.Dirent.caseinfo.HasFlag(CaseInfo.CriticalEa))
continue;
}
fileWithEa.Fat32Ea = sidecar.Value.Dirent;
@@ -993,4 +1022,6 @@ public sealed partial class FAT
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -40,6 +40,8 @@ public sealed partial class FAT
{
Dictionary<string, Dictionary<string, byte[]>> _eaCache;
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber ListXAttr(string path, out List<string> xattrs)
{
@@ -124,6 +126,8 @@ public sealed partial class FAT
return ErrorNumber.NoError;
}
#endregion
Dictionary<string, byte[]> GetEas(DirectoryEntry entryFat32Ea)
{
var eaMs = new MemoryStream();
@@ -131,7 +135,7 @@ public sealed partial class FAT
foreach(uint cluster in rootDirectoryClusters)
{
ErrorNumber errno = _image.ReadSectors(_firstClusterSector + (cluster * _sectorsPerCluster),
ErrorNumber errno = _image.ReadSectors(_firstClusterSector + cluster * _sectorsPerCluster,
_sectorsPerCluster, out byte[] buffer);
if(errno != ErrorNumber.NoError)
@@ -141,8 +145,8 @@ public sealed partial class FAT
}
byte[] full = eaMs.ToArray();
ushort size = BitConverter.ToUInt16(full, 0);
byte[] eas = new byte[size];
var size = BitConverter.ToUInt16(full, 0);
var eas = new byte[size];
Array.Copy(full, 0, eas, 0, size);
eaMs.Close();
@@ -155,11 +159,11 @@ public sealed partial class FAT
int aIndex = eaHandle >> 7;
// First 0x20 bytes are the magic number and unused words
ushort a = BitConverter.ToUInt16(_cachedEaData, (aIndex * 2) + 0x20);
var a = BitConverter.ToUInt16(_cachedEaData, aIndex * 2 + 0x20);
ushort b = BitConverter.ToUInt16(_cachedEaData, (eaHandle * 2) + 0x200);
var b = BitConverter.ToUInt16(_cachedEaData, eaHandle * 2 + 0x200);
uint eaCluster = (uint)(a + b);
var eaCluster = (uint)(a + b);
if(b == EA_UNUSED)
return null;
@@ -171,10 +175,10 @@ public sealed partial class FAT
if(header.magic != 0x4145)
return null;
uint eaLen = BitConverter.ToUInt32(_cachedEaData,
(int)(eaCluster * _bytesPerCluster) + Marshal.SizeOf<EaHeader>());
var eaLen = BitConverter.ToUInt32(_cachedEaData,
(int)(eaCluster * _bytesPerCluster) + Marshal.SizeOf<EaHeader>());
byte[] eaData = new byte[eaLen];
var eaData = new byte[eaLen];
Array.Copy(_cachedEaData, (int)(eaCluster * _bytesPerCluster) + Marshal.SizeOf<EaHeader>(), eaData, 0, eaLen);
@@ -192,19 +196,19 @@ public sealed partial class FAT
if(_debug)
eas.Add("com.microsoft.os2.fea", eaData);
int pos = 4;
var pos = 4;
while(pos < eaData.Length)
{
pos++; // Skip fEA
byte cbName = eaData[pos++];
ushort cbValue = BitConverter.ToUInt16(eaData, pos);
byte cbName = eaData[pos++];
var cbValue = BitConverter.ToUInt16(eaData, pos);
pos += 2;
string name = Encoding.ASCII.GetString(eaData, pos, cbName);
pos += cbName;
pos++;
byte[] data = new byte[cbValue];
var data = new byte[cbValue];
Array.Copy(eaData, pos, data, 0, cbValue);
pos += cbValue;
@@ -234,7 +238,7 @@ public sealed partial class FAT
foreach(uint cluster in GetClusters(_eaDirEntry.start_cluster))
{
ErrorNumber errno = _image.ReadSectors(_firstClusterSector + (cluster * _sectorsPerCluster),
ErrorNumber errno = _image.ReadSectors(_firstClusterSector + cluster * _sectorsPerCluster,
_sectorsPerCluster, out byte[] buffer);
if(errno != ErrorNumber.NoError)

View File

@@ -58,10 +58,17 @@ public sealed partial class XboxFatPlugin
// Do not translate
const string FS_TYPE = "fatx";
#region Nested type: Attributes
[Flags]
enum Attributes : byte
{
ReadOnly = 0x01, Hidden = 0x02, System = 0x04,
Directory = 0x10, Archive = 0x20
ReadOnly = 0x01,
Hidden = 0x02,
System = 0x04,
Directory = 0x10,
Archive = 0x20
}
#endregion
}

View File

@@ -37,6 +37,8 @@ namespace Aaru.Filesystems;
public sealed partial class XboxFatPlugin
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber OpenDir(string path, out IDirNode node)
{
@@ -72,10 +74,7 @@ public sealed partial class XboxFatPlugin
return ErrorNumber.NoError;
}
string[] pieces = cutPath.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pieces = cutPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
KeyValuePair<string, DirectoryEntry> entry =
_rootDirectory.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[0]);
@@ -90,7 +89,7 @@ public sealed partial class XboxFatPlugin
currentDirectory = _rootDirectory;
for(int p = 0; p < pieces.Length; p++)
for(var p = 0; p < pieces.Length; p++)
{
entry = currentDirectory.FirstOrDefault(t => t.Key.ToLower(_cultureInfo) == pieces[p]);
@@ -111,12 +110,12 @@ public sealed partial class XboxFatPlugin
if(clusters is null)
return ErrorNumber.InvalidArgument;
byte[] directoryBuffer = new byte[_bytesPerCluster * clusters.Length];
var directoryBuffer = new byte[_bytesPerCluster * clusters.Length];
for(int i = 0; i < clusters.Length; i++)
for(var i = 0; i < clusters.Length; i++)
{
ErrorNumber errno =
_imagePlugin.ReadSectors(_firstClusterSector + ((clusters[i] - 1) * _sectorsPerCluster),
_imagePlugin.ReadSectors(_firstClusterSector + (clusters[i] - 1) * _sectorsPerCluster,
_sectorsPerCluster, out byte[] buffer);
if(errno != ErrorNumber.NoError)
@@ -127,7 +126,7 @@ public sealed partial class XboxFatPlugin
currentDirectory = new Dictionary<string, DirectoryEntry>();
int pos = 0;
var pos = 0;
while(pos < directoryBuffer.Length)
{
@@ -202,4 +201,6 @@ public sealed partial class XboxFatPlugin
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -41,6 +41,7 @@ namespace Aaru.Filesystems;
/// <summary>Implements the Xbox File Allocation Table (FATX or XTAF) filesystem.</summary>
public sealed partial class XboxFatPlugin : IReadOnlyFilesystem
{
const string MODULE_NAME = "Xbox FAT plugin";
uint _bytesPerCluster;
CultureInfo _cultureInfo;
bool _debug;
@@ -58,12 +59,17 @@ public sealed partial class XboxFatPlugin : IReadOnlyFilesystem
FileSystemInfo _statfs;
Superblock _superblock;
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public FileSystem Metadata { get; private set; }
/// <inheritdoc />
public string Name => Localization.XboxFatPlugin_Name;
/// <inheritdoc />
public Guid Id => new("ED27A721-4A17-4649-89FD-33633B46E228");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
@@ -93,12 +99,10 @@ public sealed partial class XboxFatPlugin : IReadOnlyFilesystem
/// <inheritdoc />
public Dictionary<string, string> Namespaces => null;
#endregion
static Dictionary<string, string> GetDefaultOptions() => new()
{
{
"debug", false.ToString()
}
{ "debug", false.ToString() }
};
const string MODULE_NAME = "Xbox FAT plugin";
}

View File

@@ -40,6 +40,8 @@ namespace Aaru.Filesystems;
public sealed partial class XboxFatPlugin
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber GetAttributes(string path, out FileAttributes attributes)
{
@@ -131,14 +133,14 @@ public sealed partial class XboxFatPlugin
var ms = new MemoryStream();
for(int i = 0; i < sizeInClusters; i++)
for(var i = 0; i < sizeInClusters; i++)
{
if(i + firstCluster >= mynode._clusters.Length)
return ErrorNumber.InvalidArgument;
ErrorNumber errno =
_imagePlugin.
ReadSectors(_firstClusterSector + ((mynode._clusters[i + firstCluster] - 1) * _sectorsPerCluster),
ReadSectors(_firstClusterSector + (mynode._clusters[i + firstCluster] - 1) * _sectorsPerCluster,
_sectorsPerCluster, out byte[] buf);
if(errno != ErrorNumber.NoError)
@@ -226,6 +228,8 @@ public sealed partial class XboxFatPlugin
return ErrorNumber.NoError;
}
#endregion
uint[] GetClusters(uint startCluster)
{
if(startCluster == 0)
@@ -244,18 +248,22 @@ public sealed partial class XboxFatPlugin
uint nextCluster = startCluster;
if(_fat16 is null)
{
while((nextCluster & FAT32_MASK) > 0 &&
(nextCluster & FAT32_MASK) <= FAT32_RESERVED)
{
clusters.Add(nextCluster);
nextCluster = _fat32[nextCluster];
}
}
else
{
while(nextCluster is > 0 and <= FAT16_RESERVED)
{
clusters.Add(nextCluster);
nextCluster = _fat16[nextCluster];
}
}
return clusters.ToArray();
}
@@ -266,15 +274,12 @@ public sealed partial class XboxFatPlugin
string cutPath = path.StartsWith('/') ? path[1..].ToLower(_cultureInfo) : path.ToLower(_cultureInfo);
string[] pieces = cutPath.Split(new[]
{
'/'
}, StringSplitOptions.RemoveEmptyEntries);
string[] pieces = cutPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if(pieces.Length == 0)
return ErrorNumber.InvalidArgument;
string parentPath = string.Join("/", pieces, 0, pieces.Length - 1);
var parentPath = string.Join("/", pieces, 0, pieces.Length - 1);
ErrorNumber err = OpenDir(parentPath, out IDirNode node);

View File

@@ -37,6 +37,8 @@ namespace Aaru.Filesystems;
public sealed partial class XboxFatPlugin
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -63,7 +65,7 @@ public sealed partial class XboxFatPlugin
if(imagePlugin.Info.SectorSize < 512)
return;
bool bigEndian = true;
var bigEndian = true;
ErrorNumber errno = imagePlugin.ReadSector(partition.Start, out byte[] sector);
@@ -99,7 +101,7 @@ public sealed partial class XboxFatPlugin
string volumeLabel = StringHandlers.CToString(fatxSb.volumeLabel,
bigEndian ? Encoding.BigEndianUnicode : Encoding.Unicode, true);
sb.AppendFormat(Localization.Volume_label_0, volumeLabel).AppendLine();
sb.AppendFormat(Localization.Volume_label_0, volumeLabel).AppendLine();
sb.AppendFormat(Localization.Volume_serial_0_X8, fatxSb.id).AppendLine();
information = sb.ToString();
@@ -115,4 +117,6 @@ public sealed partial class XboxFatPlugin
metadata.Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / metadata.ClusterSize;
}
#endregion
}

View File

@@ -33,18 +33,7 @@ namespace Aaru.Filesystems;
public sealed partial class XboxFatPlugin
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct Superblock
{
public readonly uint magic;
public readonly uint id;
public readonly uint sectorsPerCluster;
public readonly uint rootDirectoryCluster;
// TODO: Undetermined size
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public readonly byte[] volumeLabel;
}
#region Nested type: DirectoryEntry
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct DirectoryEntry
@@ -63,22 +52,61 @@ public sealed partial class XboxFatPlugin
public readonly ushort creationDate;
}
sealed class FatxFileNode : IFileNode
{
internal uint[] _clusters;
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; set; }
}
#endregion
#region Nested type: FatxDirNode
sealed class FatxDirNode : IDirNode
{
internal DirectoryEntry[] _entries;
internal int _position;
#region IDirNode Members
/// <inheritdoc />
public string Path { get; init; }
#endregion
}
#endregion
#region Nested type: FatxFileNode
sealed class FatxFileNode : IFileNode
{
internal uint[] _clusters;
#region IFileNode Members
/// <inheritdoc />
public string Path { get; init; }
/// <inheritdoc />
public long Length { get; init; }
/// <inheritdoc />
public long Offset { get; set; }
#endregion
}
#endregion
#region Nested type: Superblock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct Superblock
{
public readonly uint magic;
public readonly uint id;
public readonly uint sectorsPerCluster;
public readonly uint rootDirectoryCluster;
// TODO: Undetermined size
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public readonly byte[] volumeLabel;
}
#endregion
}

View File

@@ -44,9 +44,11 @@ namespace Aaru.Filesystems;
public sealed partial class XboxFatPlugin
{
#region IReadOnlyFilesystem Members
/// <inheritdoc />
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
public ErrorNumber Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
Dictionary<string, string> options, string @namespace)
{
_encoding = Encoding.GetEncoding("iso-8859-15");
_littleEndian = true;
@@ -78,7 +80,8 @@ public sealed partial class XboxFatPlugin
return ErrorNumber.InvalidArgument;
AaruConsole.DebugWriteLine(MODULE_NAME,
_littleEndian ? Localization.Filesystem_is_little_endian
_littleEndian
? Localization.Filesystem_is_little_endian
: Localization.Filesystem_is_big_endian);
int logicalSectorsPerPhysicalSectors = partition.Offset == 0 && _littleEndian ? 8 : 1;
@@ -117,16 +120,16 @@ public sealed partial class XboxFatPlugin
FreeBlocks = 0 // Requires traversing the FAT
};
AaruConsole.DebugWriteLine(MODULE_NAME, "XmlFsType.ClusterSize: {0}", Metadata.ClusterSize);
AaruConsole.DebugWriteLine(MODULE_NAME, "XmlFsType.VolumeName: {0}", Metadata.VolumeName);
AaruConsole.DebugWriteLine(MODULE_NAME, "XmlFsType.ClusterSize: {0}", Metadata.ClusterSize);
AaruConsole.DebugWriteLine(MODULE_NAME, "XmlFsType.VolumeName: {0}", Metadata.VolumeName);
AaruConsole.DebugWriteLine(MODULE_NAME, "XmlFsType.VolumeSerial: {0}", Metadata.VolumeSerial);
AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Blocks: {0}", _statfs.Blocks);
AaruConsole.DebugWriteLine(MODULE_NAME, "stat.FilenameLength: {0}", _statfs.FilenameLength);
AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Id: {0}", _statfs.Id.Serial32);
AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Type: {0}", _statfs.Type);
AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Blocks: {0}", _statfs.Blocks);
AaruConsole.DebugWriteLine(MODULE_NAME, "stat.FilenameLength: {0}", _statfs.FilenameLength);
AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Id: {0}", _statfs.Id.Serial32);
AaruConsole.DebugWriteLine(MODULE_NAME, "stat.Type: {0}", _statfs.Type);
byte[] buffer;
_fatStartSector = (FAT_START / imagePlugin.Info.SectorSize) + partition.Start;
_fatStartSector = FAT_START / imagePlugin.Info.SectorSize + partition.Start;
uint fatSize;
AaruConsole.DebugWriteLine(MODULE_NAME, "fatStartSector: {0}", _fatStartSector);
@@ -158,8 +161,10 @@ public sealed partial class XboxFatPlugin
_fat32 = MemoryMarshal.Cast<byte, uint>(buffer).ToArray();
if(!_littleEndian)
for(int i = 0; i < _fat32.Length; i++)
{
for(var i = 0; i < _fat32.Length; i++)
_fat32[i] = Swapping.Swap(_fat32[i]);
}
AaruConsole.DebugWriteLine(MODULE_NAME, "fat32[0] == FATX32_ID = {0}", _fat32[0] == FATX32_ID);
@@ -193,8 +198,10 @@ public sealed partial class XboxFatPlugin
_fat16 = MemoryMarshal.Cast<byte, ushort>(buffer).ToArray();
if(!_littleEndian)
for(int i = 0; i < _fat16.Length; i++)
{
for(var i = 0; i < _fat16.Length; i++)
_fat16[i] = Swapping.Swap(_fat16[i]);
}
AaruConsole.DebugWriteLine(MODULE_NAME, "fat16[0] == FATX16_ID = {0}", _fat16[0] == FATX16_ID);
@@ -207,8 +214,8 @@ public sealed partial class XboxFatPlugin
_firstClusterSector = _fatStartSector + fatSize;
_bytesPerCluster = _sectorsPerCluster * imagePlugin.Info.SectorSize;
AaruConsole.DebugWriteLine(MODULE_NAME, "sectorsPerCluster = {0}", _sectorsPerCluster);
AaruConsole.DebugWriteLine(MODULE_NAME, "bytesPerCluster = {0}", _bytesPerCluster);
AaruConsole.DebugWriteLine(MODULE_NAME, "sectorsPerCluster = {0}", _sectorsPerCluster);
AaruConsole.DebugWriteLine(MODULE_NAME, "bytesPerCluster = {0}", _bytesPerCluster);
AaruConsole.DebugWriteLine(MODULE_NAME, "firstClusterSector = {0}", _firstClusterSector);
uint[] rootDirectoryClusters = GetClusters(_superblock.rootDirectoryCluster);
@@ -216,13 +223,13 @@ public sealed partial class XboxFatPlugin
if(rootDirectoryClusters is null)
return ErrorNumber.InvalidArgument;
byte[] rootDirectoryBuffer = new byte[_bytesPerCluster * rootDirectoryClusters.Length];
var rootDirectoryBuffer = new byte[_bytesPerCluster * rootDirectoryClusters.Length];
AaruConsole.DebugWriteLine(MODULE_NAME, Localization.Reading_root_directory);
for(int i = 0; i < rootDirectoryClusters.Length; i++)
for(var i = 0; i < rootDirectoryClusters.Length; i++)
{
errno = imagePlugin.ReadSectors(_firstClusterSector + ((rootDirectoryClusters[i] - 1) * _sectorsPerCluster),
errno = imagePlugin.ReadSectors(_firstClusterSector + (rootDirectoryClusters[i] - 1) * _sectorsPerCluster,
_sectorsPerCluster, out buffer);
if(errno != ErrorNumber.NoError)
@@ -233,7 +240,7 @@ public sealed partial class XboxFatPlugin
_rootDirectory = new Dictionary<string, DirectoryEntry>();
int pos = 0;
var pos = 0;
while(pos < rootDirectoryBuffer.Length)
{
@@ -289,4 +296,6 @@ public sealed partial class XboxFatPlugin
return ErrorNumber.NoError;
}
#endregion
}

View File

@@ -27,8 +27,8 @@
// ****************************************************************************/
using System.Diagnostics.CodeAnalysis;
using time_t = System.Int32;
using ufs_daddr_t = System.Int32;
using time_t = int;
using ufs_daddr_t = int;
namespace Aaru.Filesystems;

View File

@@ -29,8 +29,8 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Aaru.CommonTypes.Interfaces;
using time_t = System.Int32;
using ufs_daddr_t = System.Int32;
using time_t = int;
using ufs_daddr_t = int;
namespace Aaru.Filesystems;
@@ -40,11 +40,18 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "InconsistentNaming")]
public sealed partial class FFSPlugin : IFilesystem
{
const string MODULE_NAME = "FFS plugin";
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.FFSPlugin_Name;
/// <inheritdoc />
public Guid Id => new("CC90D342-05DB-48A8-988C-C1FE000034A3");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
const string MODULE_NAME = "FFS plugin";
#endregion
}

View File

@@ -36,8 +36,8 @@ using Aaru.CommonTypes.Interfaces;
using Aaru.Console;
using Aaru.Helpers;
using Partition = Aaru.CommonTypes.Partition;
using time_t = System.Int32;
using ufs_daddr_t = System.Int32;
using time_t = int;
using ufs_daddr_t = int;
namespace Aaru.Filesystems;
@@ -47,6 +47,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "InconsistentNaming")]
public sealed partial class FFSPlugin
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -77,10 +79,10 @@ public sealed partial class FFSPlugin
if(errno != ErrorNumber.NoError)
continue;
uint magic = BitConverter.ToUInt32(ufsSbSectors, 0x055C);
var magic = BitConverter.ToUInt32(ufsSbSectors, 0x055C);
if(magic is UFS_MAGIC or UFS_CIGAM or UFS_MAGIC_BW or UFS_CIGAM_BW or UFS2_MAGIC or UFS2_CIGAM
or UFS_BAD_MAGIC or UFS_BAD_CIGAM)
or UFS_BAD_MAGIC or UFS_BAD_CIGAM)
return true;
}
@@ -104,13 +106,13 @@ public sealed partial class FFSPlugin
uint sb_size_in_sectors;
byte[] ufs_sb_sectors;
ulong sb_offset = partition.Start;
bool fs_type_42bsd = false;
bool fs_type_43bsd = false;
bool fs_type_44bsd = false;
bool fs_type_ufs = false;
bool fs_type_ufs2 = false;
bool fs_type_sun = false;
bool fs_type_sun86 = false;
var fs_type_42bsd = false;
var fs_type_43bsd = false;
var fs_type_44bsd = false;
var fs_type_ufs = false;
var fs_type_ufs2 = false;
var fs_type_sun = false;
var fs_type_sun86 = false;
if(imagePlugin.Info.SectorSize is 2336 or 2352 or 2448)
sb_size_in_sectors = block_size / 2048;
@@ -136,7 +138,7 @@ public sealed partial class FFSPlugin
magic = BitConverter.ToUInt32(ufs_sb_sectors, 0x055C);
if(magic is UFS_MAGIC or UFS_CIGAM or UFS_MAGIC_BW or UFS_CIGAM_BW or UFS2_MAGIC or UFS2_CIGAM
or UFS_BAD_MAGIC or UFS_BAD_CIGAM)
or UFS_BAD_MAGIC or UFS_BAD_CIGAM)
{
sb_offset = partition.Start + loc;
@@ -211,10 +213,10 @@ public sealed partial class FFSPlugin
SuperBlock bs_sfu = Marshal.ByteArrayToStructureBigEndian<SuperBlock>(ufs_sb_sectors);
if((bs_sfu.fs_magic == UFS_MAGIC && sb.fs_magic == UFS_CIGAM) ||
(bs_sfu.fs_magic == UFS_MAGIC_BW && sb.fs_magic == UFS_CIGAM_BW) ||
(bs_sfu.fs_magic == UFS2_MAGIC && sb.fs_magic == UFS2_CIGAM) ||
(bs_sfu.fs_magic == UFS_BAD_MAGIC && sb.fs_magic == UFS_BAD_CIGAM))
if(bs_sfu.fs_magic == UFS_MAGIC && sb.fs_magic == UFS_CIGAM ||
bs_sfu.fs_magic == UFS_MAGIC_BW && sb.fs_magic == UFS_CIGAM_BW ||
bs_sfu.fs_magic == UFS2_MAGIC && sb.fs_magic == UFS2_CIGAM ||
bs_sfu.fs_magic == UFS_BAD_MAGIC && sb.fs_magic == UFS_BAD_CIGAM)
{
sb = bs_sfu;
sb.fs_old_cstotal.cs_nbfree = Swapping.Swap(sb.fs_old_cstotal.cs_nbfree);
@@ -231,45 +233,45 @@ public sealed partial class FFSPlugin
sb.fs_cstotal.cs_spare[2] = Swapping.Swap(sb.fs_cstotal.cs_spare[2]);
}
AaruConsole.DebugWriteLine(MODULE_NAME, "sb offset: 0x{0:X8}", sb_offset);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_rlink: 0x{0:X8}", sb.fs_rlink);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_sblkno: 0x{0:X8}", sb.fs_sblkno);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cblkno: 0x{0:X8}", sb.fs_cblkno);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_iblkno: 0x{0:X8}", sb.fs_iblkno);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_dblkno: 0x{0:X8}", sb.fs_dblkno);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_size: 0x{0:X8}", sb.fs_size);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_dsize: 0x{0:X8}", sb.fs_dsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ncg: 0x{0:X8}", sb.fs_ncg);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bsize: 0x{0:X8}", sb.fs_bsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fsize: 0x{0:X8}", sb.fs_fsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_frag: 0x{0:X8}", sb.fs_frag);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_minfree: 0x{0:X8}", sb.fs_minfree);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bmask: 0x{0:X8}", sb.fs_bmask);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fmask: 0x{0:X8}", sb.fs_fmask);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bshift: 0x{0:X8}", sb.fs_bshift);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fshift: 0x{0:X8}", sb.fs_fshift);
AaruConsole.DebugWriteLine(MODULE_NAME, "sb offset: 0x{0:X8}", sb_offset);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_rlink: 0x{0:X8}", sb.fs_rlink);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_sblkno: 0x{0:X8}", sb.fs_sblkno);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cblkno: 0x{0:X8}", sb.fs_cblkno);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_iblkno: 0x{0:X8}", sb.fs_iblkno);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_dblkno: 0x{0:X8}", sb.fs_dblkno);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_size: 0x{0:X8}", sb.fs_size);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_dsize: 0x{0:X8}", sb.fs_dsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ncg: 0x{0:X8}", sb.fs_ncg);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bsize: 0x{0:X8}", sb.fs_bsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fsize: 0x{0:X8}", sb.fs_fsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_frag: 0x{0:X8}", sb.fs_frag);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_minfree: 0x{0:X8}", sb.fs_minfree);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bmask: 0x{0:X8}", sb.fs_bmask);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fmask: 0x{0:X8}", sb.fs_fmask);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_bshift: 0x{0:X8}", sb.fs_bshift);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fshift: 0x{0:X8}", sb.fs_fshift);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_maxcontig: 0x{0:X8}", sb.fs_maxcontig);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_maxbpg: 0x{0:X8}", sb.fs_maxbpg);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_maxbpg: 0x{0:X8}", sb.fs_maxbpg);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fragshift: 0x{0:X8}", sb.fs_fragshift);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fsbtodb: 0x{0:X8}", sb.fs_fsbtodb);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_sbsize: 0x{0:X8}", sb.fs_sbsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csmask: 0x{0:X8}", sb.fs_csmask);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csshift: 0x{0:X8}", sb.fs_csshift);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_nindir: 0x{0:X8}", sb.fs_nindir);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_inopb: 0x{0:X8}", sb.fs_inopb);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_optim: 0x{0:X8}", sb.fs_optim);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_id_1: 0x{0:X8}", sb.fs_id_1);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_id_2: 0x{0:X8}", sb.fs_id_2);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csaddr: 0x{0:X8}", sb.fs_csaddr);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cssize: 0x{0:X8}", sb.fs_cssize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cgsize: 0x{0:X8}", sb.fs_cgsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ipg: 0x{0:X8}", sb.fs_ipg);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fpg: 0x{0:X8}", sb.fs_fpg);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fmod: 0x{0:X2}", sb.fs_fmod);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_clean: 0x{0:X2}", sb.fs_clean);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ronly: 0x{0:X2}", sb.fs_ronly);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_flags: 0x{0:X2}", sb.fs_flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_magic: 0x{0:X8}", sb.fs_magic);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fsbtodb: 0x{0:X8}", sb.fs_fsbtodb);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_sbsize: 0x{0:X8}", sb.fs_sbsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csmask: 0x{0:X8}", sb.fs_csmask);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csshift: 0x{0:X8}", sb.fs_csshift);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_nindir: 0x{0:X8}", sb.fs_nindir);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_inopb: 0x{0:X8}", sb.fs_inopb);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_optim: 0x{0:X8}", sb.fs_optim);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_id_1: 0x{0:X8}", sb.fs_id_1);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_id_2: 0x{0:X8}", sb.fs_id_2);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_csaddr: 0x{0:X8}", sb.fs_csaddr);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cssize: 0x{0:X8}", sb.fs_cssize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_cgsize: 0x{0:X8}", sb.fs_cgsize);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ipg: 0x{0:X8}", sb.fs_ipg);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fpg: 0x{0:X8}", sb.fs_fpg);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_fmod: 0x{0:X2}", sb.fs_fmod);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_clean: 0x{0:X2}", sb.fs_clean);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_ronly: 0x{0:X2}", sb.fs_ronly);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_flags: 0x{0:X2}", sb.fs_flags);
AaruConsole.DebugWriteLine(MODULE_NAME, "fs_magic: 0x{0:X8}", sb.fs_magic);
if(sb.fs_magic == UFS2_MAGIC)
fs_type_ufs2 = true;
@@ -351,10 +353,10 @@ public sealed partial class FFSPlugin
if(fs_type_42bsd)
sbInformation.AppendFormat(Localization.Linked_list_of_filesystems_0, sb.fs_link).AppendLine();
sbInformation.AppendFormat(Localization.Superblock_LBA_0, sb.fs_sblkno).AppendLine();
sbInformation.AppendFormat(Localization.Cylinder_block_LBA_0, sb.fs_cblkno).AppendLine();
sbInformation.AppendFormat(Localization.inode_block_LBA_0, sb.fs_iblkno).AppendLine();
sbInformation.AppendFormat(Localization.First_data_block_LBA_0, sb.fs_dblkno).AppendLine();
sbInformation.AppendFormat(Localization.Superblock_LBA_0, sb.fs_sblkno).AppendLine();
sbInformation.AppendFormat(Localization.Cylinder_block_LBA_0, sb.fs_cblkno).AppendLine();
sbInformation.AppendFormat(Localization.inode_block_LBA_0, sb.fs_iblkno).AppendLine();
sbInformation.AppendFormat(Localization.First_data_block_LBA_0, sb.fs_dblkno).AppendLine();
sbInformation.AppendFormat(Localization.Cylinder_group_offset_in_cylinder_0, sb.fs_old_cgoffset).AppendLine();
sbInformation.AppendFormat(Localization.Volume_last_written_on_0, DateHandlers.UnixToDateTime(sb.fs_old_time)).
@@ -372,10 +374,10 @@ public sealed partial class FFSPlugin
(long)sb.fs_old_dsize * sb.fs_fsize).AppendLine();
sbInformation.AppendFormat(Localization._0_cylinder_groups_in_volume, sb.fs_ncg).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_in_a_basic_block, sb.fs_bsize).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_in_a_frag_block, sb.fs_fsize).AppendLine();
sbInformation.AppendFormat(Localization._0_frags_in_a_block, sb.fs_frag).AppendLine();
sbInformation.AppendFormat(Localization._0_of_blocks_must_be_free, sb.fs_minfree).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_in_a_basic_block, sb.fs_bsize).AppendLine();
sbInformation.AppendFormat(Localization._0_bytes_in_a_frag_block, sb.fs_fsize).AppendLine();
sbInformation.AppendFormat(Localization._0_frags_in_a_block, sb.fs_frag).AppendLine();
sbInformation.AppendFormat(Localization._0_of_blocks_must_be_free, sb.fs_minfree).AppendLine();
sbInformation.AppendFormat(Localization._0_ms_for_optimal_next_block, sb.fs_old_rotdelay).AppendLine();
sbInformation.
@@ -386,12 +388,12 @@ public sealed partial class FFSPlugin
sbInformation.AppendFormat("fs_fmask: 0x{0:X8}", sb.fs_fmask).AppendLine();
sbInformation.AppendFormat("fs_bshift: 0x{0:X8}", sb.fs_bshift).AppendLine();
sbInformation.AppendFormat("fs_fshift: 0x{0:X8}", sb.fs_fshift).AppendLine();*/
sbInformation.AppendFormat(Localization._0_contiguous_blocks_at_maximum, sb.fs_maxcontig).AppendLine();
sbInformation.AppendFormat(Localization._0_contiguous_blocks_at_maximum, sb.fs_maxcontig).AppendLine();
sbInformation.AppendFormat(Localization._0_blocks_per_cylinder_group_at_maximum, sb.fs_maxbpg).AppendLine();
sbInformation.AppendFormat(Localization.Superblock_is_0_bytes, sb.fs_sbsize).AppendLine();
sbInformation.AppendFormat(Localization.NINDIR_0, sb.fs_nindir).AppendLine();
sbInformation.AppendFormat(Localization.INOPB_0, sb.fs_inopb).AppendLine();
sbInformation.AppendFormat(Localization.NSPF_0, sb.fs_old_nspf).AppendLine();
sbInformation.AppendFormat(Localization.Superblock_is_0_bytes, sb.fs_sbsize).AppendLine();
sbInformation.AppendFormat(Localization.NINDIR_0, sb.fs_nindir).AppendLine();
sbInformation.AppendFormat(Localization.INOPB_0, sb.fs_inopb).AppendLine();
sbInformation.AppendFormat(Localization.NSPF_0, sb.fs_old_nspf).AppendLine();
switch(sb.fs_optim)
{
@@ -412,11 +414,13 @@ public sealed partial class FFSPlugin
if(fs_type_sun)
sbInformation.AppendFormat(Localization._0_sectors_track, sb.fs_old_npsect).AppendLine();
else if(fs_type_sun86)
{
sbInformation.AppendFormat(Localization.Volume_state_on_0, DateHandlers.UnixToDateTime(sb.fs_old_npsect)).
AppendLine();
}
sbInformation.AppendFormat(Localization.Hardware_sector_interleave_0, sb.fs_old_interleave).AppendLine();
sbInformation.AppendFormat(Localization.Sector_zero_skew_0_track, sb.fs_old_trackskew).AppendLine();
sbInformation.AppendFormat(Localization.Sector_zero_skew_0_track, sb.fs_old_trackskew).AppendLine();
switch(fs_type_43bsd)
{
@@ -425,7 +429,7 @@ public sealed partial class FFSPlugin
break;
case true when sb is { fs_id_1: > 0, fs_id_2: > 0 }:
sbInformation.AppendFormat(Localization._0_µsec_for_head_switch, sb.fs_id_1).AppendLine();
sbInformation.AppendFormat(Localization._0_µsec_for_head_switch, sb.fs_id_1).AppendLine();
sbInformation.AppendFormat(Localization._0_µsec_for_track_to_track_seek, sb.fs_id_2).AppendLine();
break;
@@ -448,7 +452,7 @@ public sealed partial class FFSPlugin
metadata.FreeClusters = (ulong)sb.fs_old_cstotal.cs_nbfree;
sbInformation.AppendFormat(Localization._0_free_inodes, sb.fs_old_cstotal.cs_nifree).AppendLine();
sbInformation.AppendFormat(Localization._0_free_frags, sb.fs_old_cstotal.cs_nffree).AppendLine();
sbInformation.AppendFormat(Localization._0_free_frags, sb.fs_old_cstotal.cs_nffree).AppendLine();
if(sb.fs_fmod == 1)
{
@@ -465,8 +469,10 @@ public sealed partial class FFSPlugin
sbInformation.AppendFormat(Localization.Volume_flags_0_X2, sb.fs_flags).AppendLine();
if(fs_type_ufs)
{
sbInformation.AppendFormat(Localization.Volume_last_mounted_at_0, StringHandlers.CToString(sb.fs_fsmnt)).
AppendLine();
}
else if(fs_type_ufs2)
{
sbInformation.AppendFormat(Localization.Volume_last_mounted_at_0, StringHandlers.CToString(sb.fs_fsmnt)).
@@ -485,14 +491,14 @@ public sealed partial class FFSPlugin
AppendLine();
sbInformation.AppendFormat(Localization.Standard_superblock_LBA_0, sb.fs_sblkno).AppendLine();
sbInformation.AppendFormat(Localization._0_directories, sb.fs_cstotal.cs_ndir).AppendLine();
sbInformation.AppendFormat(Localization._0_directories, sb.fs_cstotal.cs_ndir).AppendLine();
sbInformation.AppendFormat(Localization._0_free_blocks_1_bytes, sb.fs_cstotal.cs_nbfree,
sb.fs_cstotal.cs_nbfree * sb.fs_fsize).AppendLine();
metadata.FreeClusters = (ulong)sb.fs_cstotal.cs_nbfree;
sbInformation.AppendFormat(Localization._0_free_inodes, sb.fs_cstotal.cs_nifree).AppendLine();
sbInformation.AppendFormat(Localization._0_free_frags, sb.fs_cstotal.cs_nffree).AppendLine();
sbInformation.AppendFormat(Localization._0_free_inodes, sb.fs_cstotal.cs_nifree).AppendLine();
sbInformation.AppendFormat(Localization._0_free_frags, sb.fs_cstotal.cs_nffree).AppendLine();
sbInformation.AppendFormat(Localization._0_free_clusters, sb.fs_cstotal.cs_numclusters).AppendLine();
sbInformation.AppendFormat(Localization.Volume_last_written_on_0, DateHandlers.UnixToDateTime(sb.fs_time)).
@@ -514,8 +520,10 @@ public sealed partial class FFSPlugin
}
if(fs_type_sun)
{
sbInformation.AppendFormat(Localization.Volume_state_on_0, DateHandlers.UnixToDateTime(sb.fs_old_npsect)).
AppendLine();
}
else if(fs_type_sun86)
sbInformation.AppendFormat(Localization._0_sectors_track, sb.fs_state).AppendLine();
else if(fs_type_44bsd)
@@ -540,4 +548,6 @@ public sealed partial class FFSPlugin
information = sbInformation.ToString();
}
#endregion
}

View File

@@ -28,8 +28,8 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using time_t = System.Int32;
using ufs_daddr_t = System.Int32;
using time_t = int;
using ufs_daddr_t = int;
namespace Aaru.Filesystems;
@@ -39,6 +39,8 @@ namespace Aaru.Filesystems;
[SuppressMessage("ReSharper", "InconsistentNaming")]
public sealed partial class FFSPlugin
{
#region Nested type: csum
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct csum
{
@@ -52,6 +54,10 @@ public sealed partial class FFSPlugin
public int cs_nffree;
}
#endregion
#region Nested type: csum_total
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct csum_total
{
@@ -70,6 +76,10 @@ public sealed partial class FFSPlugin
public readonly long[] cs_spare;
}
#endregion
#region Nested type: SuperBlock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct SuperBlock
{
@@ -289,4 +299,6 @@ public sealed partial class FFSPlugin
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public readonly byte[] fs_rotbl;
}
#endregion
}

View File

@@ -35,11 +35,18 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection for the Plan-9 Fossil on-disk filesystem</summary>
public sealed partial class Fossil : IFilesystem
{
const string MODULE_NAME = "Fossil plugin";
#region IFilesystem Members
/// <inheritdoc />
public string Name => Localization.Fossil_Name;
/// <inheritdoc />
public Guid Id => new("932BF104-43F6-494F-973C-45EF58A51DA9");
/// <inheritdoc />
public string Author => Authors.NataliaPortillo;
const string MODULE_NAME = "Fossil plugin";
#endregion
}

View File

@@ -40,6 +40,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection for the Plan-9 Fossil on-disk filesystem</summary>
public sealed partial class Fossil
{
#region IFilesystem Members
/// <inheritdoc />
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
@@ -86,14 +88,14 @@ public sealed partial class Fossil
var sb = new StringBuilder();
sb.AppendLine(Localization.Fossil_filesystem);
sb.AppendFormat(Localization.Filesystem_version_0, hdr.version).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_block, hdr.blockSize).AppendLine();
sb.AppendFormat(Localization.Filesystem_version_0, hdr.version).AppendLine();
sb.AppendFormat(Localization._0_bytes_per_block, hdr.blockSize).AppendLine();
sb.AppendFormat(Localization.Superblock_resides_in_block_0, hdr.super).AppendLine();
sb.AppendFormat(Localization.Labels_resides_in_block_0, hdr.label).AppendLine();
sb.AppendFormat(Localization.Data_starts_at_block_0, hdr.data).AppendLine();
sb.AppendFormat(Localization.Volume_has_0_blocks, hdr.end).AppendLine();
sb.AppendFormat(Localization.Labels_resides_in_block_0, hdr.label).AppendLine();
sb.AppendFormat(Localization.Data_starts_at_block_0, hdr.data).AppendLine();
sb.AppendFormat(Localization.Volume_has_0_blocks, hdr.end).AppendLine();
ulong sbLocation = (hdr.super * (hdr.blockSize / imagePlugin.Info.SectorSize)) + partition.Start;
ulong sbLocation = hdr.super * (hdr.blockSize / imagePlugin.Info.SectorSize) + partition.Start;
metadata = new FileSystem
{
@@ -124,4 +126,6 @@ public sealed partial class Fossil
information = sb.ToString();
}
#endregion
}

View File

@@ -34,6 +34,8 @@ namespace Aaru.Filesystems;
/// <summary>Implements detection for the Plan-9 Fossil on-disk filesystem</summary>
public sealed partial class Fossil
{
#region Nested type: Header
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct Header
{
@@ -53,6 +55,10 @@ public sealed partial class Fossil
public readonly uint end;
}
#endregion
#region Nested type: SuperBlock
[StructLayout(LayoutKind.Sequential, Pack = 1)]
readonly struct SuperBlock
{
@@ -79,4 +85,6 @@ public sealed partial class Fossil
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public readonly byte[] name;
}
#endregion
}

View File

@@ -26,9 +26,9 @@
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using hammer_crc_t = System.UInt32;
using hammer_off_t = System.UInt64;
using hammer_tid_t = System.UInt64;
using hammer_crc_t = uint;
using hammer_off_t = ulong;
using hammer_tid_t = ulong;
#pragma warning disable 169

Some files were not shown because too many files have changed in this diff Show More