using System; using System.Collections.Generic; using System.Text; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs; using Aaru.Core; using NUnit.Framework; namespace Aaru.Tests.Issues; /// This will extract (and discard data) all files in all filesystems detected in an image. public abstract class FsExtractIssueTest { public abstract string DataFolder { get; } public abstract string TestFile { get; } public abstract Dictionary 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; } [OneTimeSetUp] public void InitTest() => PluginBase.Init(); [Test] public void Test() { Environment.CurrentDirectory = DataFolder; IFilter inputFilter = PluginRegister.Singleton.GetFilter(TestFile); Dictionary options = ParsedOptions; options["debug"] = Debug.ToString(); Assert.That(inputFilter, Is.Not.Null, Localization.Cannot_open_specified_file); Encoding encodingClass = null; if(Encoding != null) encodingClass = Claunia.Encoding.Encoding.GetEncoding(Encoding); PluginRegister plugins = PluginRegister.Singleton; var imageFormat = ImageFormat.Detect(inputFilter) as IMediaImage; Assert.That(imageFormat, Is.Not.Null, Localization.Image_format_not_identified_not_proceeding_with_analysis); Assert.That(imageFormat.Open(inputFilter), Is.EqualTo(ErrorNumber.NoError), Localization.Unable_to_open_image_format); List partitions = Core.Partitions.GetAll(imageFormat); if(partitions.Count == 0) { Assert.That(ExpectPartitions, Is.False, Localization.No_partitions_found); partitions.Add(new Partition { Description = "Whole device", Length = imageFormat.Info.Sectors, Offset = 0, Size = imageFormat.Info.SectorSize * imageFormat.Info.Sectors, Sequence = 1, Start = 0 }); } var filesystemFound = false; for(var i = 0; i < partitions.Count; i++) { Core.Filesystems.Identify(imageFormat, out List idPlugins, partitions[i]); if(idPlugins.Count == 0) continue; ErrorNumber error; if(idPlugins.Count > 1) { foreach(string pluginName in idPlugins) { if(!plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out IReadOnlyFilesystem fs)) continue; Assert.That(fs, Is.Not.Null, string.Format(Localization.Could_not_instantiate_filesystem_0, pluginName)); filesystemFound = true; error = fs.Mount(imageFormat, partitions[i], encodingClass, options, Namespace); Assert.That(error, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Could_not_mount_0_in_partition_1, pluginName, i)); ExtractFilesInDir("/", fs, Xattrs); } } else { plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out IReadOnlyFilesystem fs); Assert.That(fs, Is.Not.Null, string.Format(Localization.Could_not_instantiate_filesystem_0, fs?.Name)); filesystemFound = true; error = fs.Mount(imageFormat, partitions[i], encodingClass, options, Namespace); Assert.That(error, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Could_not_mount_0_in_partition_1, fs.Name, i)); ExtractFilesInDir("/", fs, Xattrs); } } Assert.That(filesystemFound, Localization.No_filesystems_found); } static void ExtractFilesInDir(string path, IReadOnlyFilesystem fs, bool doXattrs) { if(path.StartsWith('/')) path = path[1..]; ErrorNumber error = fs.OpenDir(path, out IDirNode node); Assert.That(error, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Error_0_reading_root_directory, error.ToString())); while(fs.ReadDir(node, out string entry) == ErrorNumber.NoError && entry is not null) { error = fs.Stat(path + "/" + entry, out FileEntryInfo stat); Assert.That(error, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Error_getting_stat_for_entry_0, entry)); if(stat.Attributes.HasFlag(FileAttributes.Directory)) { ExtractFilesInDir(path + "/" + entry, fs, doXattrs); continue; } if(doXattrs) { error = fs.ListXAttr(path + "/" + entry, out List xattrs); Assert.That(error, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Error_0_getting_extended_attributes_for_entry_1, error, path + "/" + entry)); if(error == ErrorNumber.NoError) { foreach(string xattr in xattrs) { byte[] xattrBuf = []; error = fs.GetXattr(path + "/" + entry, xattr, ref xattrBuf); Assert.That(error, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Error_0_reading_extended_attributes_for_entry_1, error, path + "/" + entry)); } } } var buffer = new byte[stat.Length]; ErrorNumber ret = fs.OpenFile(path + "/" + entry, out IFileNode fileNode); Assert.That(ret, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Error_0_reading_file_1, ret, path + "/" + entry)); ret = fs.ReadFile(fileNode, stat.Length, buffer, out long readBytes); Assert.That(ret, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Error_0_reading_file_1, ret, path + "/" + entry)); Assert.That(readBytes, Is.EqualTo(stat.Length), string.Format(Localization.Error_0_reading_file_1, readBytes, stat.Length, path + "/" + entry)); } fs.CloseDir(node); } }