2021-03-07 19:22:17 +00:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using Aaru.CommonTypes;
|
2021-09-16 04:42:14 +01:00
|
|
|
using Aaru.CommonTypes.Enums;
|
2021-03-07 19:22:17 +00:00
|
|
|
using Aaru.CommonTypes.Interfaces;
|
|
|
|
|
using Aaru.CommonTypes.Structs;
|
|
|
|
|
using Aaru.Core;
|
|
|
|
|
using NUnit.Framework;
|
|
|
|
|
|
2022-11-15 15:58:43 +00:00
|
|
|
namespace Aaru.Tests.Issues;
|
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
/// <summary>This will extract (and discard data) all files in all filesystems detected in an image.</summary>
|
|
|
|
|
public abstract class FsExtractIssueTest
|
2021-03-07 19:22:17 +00:00
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
public abstract string DataFolder { get; }
|
|
|
|
|
public abstract string TestFile { get; }
|
|
|
|
|
public abstract Dictionary<string, string> ParsedOptions { get; }
|
|
|
|
|
public abstract bool Debug { get; }
|
|
|
|
|
public abstract bool Xattrs { get; }
|
|
|
|
|
public abstract string Encoding { get; }
|
|
|
|
|
public abstract bool ExpectPartitions { get; }
|
|
|
|
|
public abstract string Namespace { get; }
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void Test()
|
2021-03-07 19:22:17 +00:00
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
Environment.CurrentDirectory = DataFolder;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
var filtersList = new FiltersList();
|
|
|
|
|
IFilter inputFilter = filtersList.GetFilter(TestFile);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
Dictionary<string, string> options = ParsedOptions;
|
|
|
|
|
options["debug"] = Debug.ToString();
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-11-29 10:33:40 +00:00
|
|
|
Assert.IsNotNull(inputFilter, Localization.Cannot_open_specified_file);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
Encoding encodingClass = null;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
if(Encoding != null)
|
|
|
|
|
encodingClass = Claunia.Encoding.Encoding.GetEncoding(Encoding);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 20:50:17 +00:00
|
|
|
PluginBase plugins = PluginBase.Singleton;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-07 07:36:44 +00:00
|
|
|
var imageFormat = ImageFormat.Detect(inputFilter) as IMediaImage;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-11-29 10:33:40 +00:00
|
|
|
Assert.NotNull(imageFormat, Localization.Image_format_not_identified_not_proceeding_with_analysis);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-11-29 10:33:40 +00:00
|
|
|
Assert.AreEqual(ErrorNumber.NoError, imageFormat.Open(inputFilter), Localization.Unable_to_open_image_format);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-11-15 15:58:43 +00:00
|
|
|
List<Partition> partitions = Core.Partitions.GetAll(imageFormat);
|
2022-03-06 13:29:38 +00:00
|
|
|
|
|
|
|
|
if(partitions.Count == 0)
|
|
|
|
|
{
|
2022-11-29 10:33:40 +00:00
|
|
|
Assert.IsFalse(ExpectPartitions, Localization.No_partitions_found);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
partitions.Add(new Partition
|
2021-03-07 19:22:17 +00:00
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
Description = "Whole device",
|
|
|
|
|
Length = imageFormat.Info.Sectors,
|
|
|
|
|
Offset = 0,
|
|
|
|
|
Size = imageFormat.Info.SectorSize * imageFormat.Info.Sectors,
|
|
|
|
|
Sequence = 1,
|
|
|
|
|
Start = 0
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2023-10-03 23:44:33 +01:00
|
|
|
var filesystemFound = false;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2023-10-03 23:44:33 +01:00
|
|
|
for(var i = 0; i < partitions.Count; i++)
|
2022-03-06 13:29:38 +00:00
|
|
|
{
|
2022-11-15 15:58:43 +00:00
|
|
|
Core.Filesystems.Identify(imageFormat, out List<string> idPlugins, partitions[i]);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
if(idPlugins.Count == 0)
|
|
|
|
|
continue;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
Type pluginType;
|
|
|
|
|
ErrorNumber error;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
if(idPlugins.Count > 1)
|
|
|
|
|
{
|
|
|
|
|
foreach(string pluginName in idPlugins)
|
2023-10-03 23:44:33 +01:00
|
|
|
{
|
2022-12-17 14:56:37 +00:00
|
|
|
if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out pluginType))
|
2022-03-06 13:29:38 +00:00
|
|
|
{
|
2022-12-17 14:56:37 +00:00
|
|
|
Assert.IsNotNull(pluginType, Localization.Could_not_instantiate_filesystem_plugin);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
var fs = Activator.CreateInstance(pluginType) as IReadOnlyFilesystem;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
Assert.IsNotNull(fs,
|
|
|
|
|
string.Format(Localization.Could_not_instantiate_filesystem_0, pluginName));
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
filesystemFound = true;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
error = fs.Mount(imageFormat, partitions[i], encodingClass, options, Namespace);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
Assert.AreEqual(ErrorNumber.NoError, error,
|
|
|
|
|
string.Format(Localization.Could_not_mount_0_in_partition_1, pluginName, i));
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
ExtractFilesInDir("/", fs, Xattrs);
|
|
|
|
|
}
|
2023-10-03 23:44:33 +01:00
|
|
|
}
|
2022-03-06 13:29:38 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-12-17 14:56:37 +00:00
|
|
|
plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out pluginType);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
if(pluginType is null)
|
2022-03-06 13:29:38 +00:00
|
|
|
continue;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
var fs = Activator.CreateInstance(pluginType) as IReadOnlyFilesystem;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
Assert.IsNotNull(fs, string.Format(Localization.Could_not_instantiate_filesystem_0, fs.Name));
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
filesystemFound = true;
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
error = fs.Mount(imageFormat, partitions[i], encodingClass, options, Namespace);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
Assert.AreEqual(ErrorNumber.NoError, error,
|
|
|
|
|
string.Format(Localization.Could_not_mount_0_in_partition_1, fs.Name, i));
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
ExtractFilesInDir("/", fs, Xattrs);
|
2021-03-07 19:22:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-29 10:33:40 +00:00
|
|
|
Assert.IsTrue(filesystemFound, Localization.No_filesystems_found);
|
2022-03-06 13:29:38 +00:00
|
|
|
}
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
static void ExtractFilesInDir(string path, IReadOnlyFilesystem fs, bool doXattrs)
|
|
|
|
|
{
|
|
|
|
|
if(path.StartsWith('/'))
|
|
|
|
|
path = path[1..];
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-21 20:03:24 +00:00
|
|
|
ErrorNumber error = fs.OpenDir(path, out IDirNode node);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
Assert.AreEqual(ErrorNumber.NoError, error,
|
2023-10-03 14:17:40 +01:00
|
|
|
string.Format(Localization.Error_0_reading_root_directory, error.ToString()));
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-21 20:03:24 +00:00
|
|
|
while(fs.ReadDir(node, out string entry) == ErrorNumber.NoError &&
|
|
|
|
|
entry is not null)
|
2022-03-06 13:29:38 +00:00
|
|
|
{
|
|
|
|
|
error = fs.Stat(path + "/" + entry, out FileEntryInfo stat);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-17 14:56:37 +00:00
|
|
|
Assert.AreEqual(ErrorNumber.NoError, error,
|
|
|
|
|
string.Format(Localization.Error_getting_stat_for_entry_0, entry));
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
if(stat.Attributes.HasFlag(FileAttributes.Directory))
|
|
|
|
|
{
|
|
|
|
|
ExtractFilesInDir(path + "/" + entry, fs, doXattrs);
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
if(doXattrs)
|
|
|
|
|
{
|
|
|
|
|
error = fs.ListXAttr(path + "/" + entry, out List<string> xattrs);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
Assert.AreEqual(ErrorNumber.NoError, error,
|
2022-12-17 14:56:37 +00:00
|
|
|
string.Format(Localization.Error_0_getting_extended_attributes_for_entry_1, error,
|
|
|
|
|
path + "/" + entry));
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
if(error == ErrorNumber.NoError)
|
2023-10-03 23:44:33 +01:00
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
foreach(string xattr in xattrs)
|
|
|
|
|
{
|
|
|
|
|
byte[] xattrBuf = Array.Empty<byte>();
|
|
|
|
|
error = fs.GetXattr(path + "/" + entry, xattr, ref xattrBuf);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
Assert.AreEqual(ErrorNumber.NoError, error,
|
2022-12-17 14:56:37 +00:00
|
|
|
string.Format(Localization.Error_0_reading_extended_attributes_for_entry_1,
|
|
|
|
|
error, path + "/" + entry));
|
2022-03-06 13:29:38 +00:00
|
|
|
}
|
2023-10-03 23:44:33 +01:00
|
|
|
}
|
2022-03-06 13:29:38 +00:00
|
|
|
}
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2023-10-03 23:44:33 +01:00
|
|
|
var buffer = new byte[stat.Length];
|
2022-12-19 11:03:51 +00:00
|
|
|
ErrorNumber ret = fs.OpenFile(path + "/" + entry, out IFileNode fileNode);
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-19 11:03:51 +00:00
|
|
|
Assert.AreEqual(ErrorNumber.NoError, ret,
|
|
|
|
|
string.Format(Localization.Error_0_reading_file_1, ret, path + "/" + entry));
|
2021-03-07 19:22:17 +00:00
|
|
|
|
2022-12-19 11:03:51 +00:00
|
|
|
ret = fs.ReadFile(fileNode, stat.Length, buffer, out long readBytes);
|
|
|
|
|
|
|
|
|
|
Assert.AreEqual(ErrorNumber.NoError, ret,
|
|
|
|
|
string.Format(Localization.Error_0_reading_file_1, ret, path + "/" + entry));
|
|
|
|
|
|
|
|
|
|
Assert.AreEqual(stat.Length, readBytes,
|
|
|
|
|
string.Format(Localization.Error_0_reading_file_1, readBytes, stat.Length,
|
|
|
|
|
path + "/" + entry));
|
2021-03-07 19:22:17 +00:00
|
|
|
}
|
2022-12-21 20:03:24 +00:00
|
|
|
|
|
|
|
|
fs.CloseDir(node);
|
2021-03-07 19:22:17 +00:00
|
|
|
}
|
|
|
|
|
}
|