mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
[Aaru.Filesystems] Reformat and cleanup.
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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() }
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 <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 >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 <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 >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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 < 0.97 indicator for normal EAs present</summary>
|
||||
NormalEaOld = 0xEA,
|
||||
/// <summary>FAT32.IFS < 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user