Dictionary <string, FileData> BuildDirectory(IReadOnlyFilesystem fs, string path) { if (path == "/") { path = ""; } Dictionary <string, FileData> children = new Dictionary <string, FileData>(); fs.ReadDir(path, out List <string> contents); foreach (string child in contents) { string childPath = $"{path}/{child}"; fs.Stat(childPath, out FileEntryInfo stat); var data = new FileData { Info = stat }; if (stat.Attributes.HasFlag(FileAttributes.Directory)) { data.Children = BuildDirectory(fs, childPath); } else { data.MD5 = BuildFile(fs, childPath, stat.Length); } children[child] = data; } return(children); }
public void Stat() { Errno error = _fs.Stat("Content/0000000000000000/FFFE07DF/00040000", out FileEntryInfo stat); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(new DateTime(2013, 9, 25, 12, 49, 46, DateTimeKind.Utc), stat.AccessTimeUtc); Assert.AreEqual(FileAttributes.Directory, stat.Attributes); Assert.AreEqual(null, stat.BackupTimeUtc); Assert.AreEqual(1, stat.Blocks); Assert.AreEqual(16384, stat.BlockSize); Assert.AreEqual(new DateTime(2013, 9, 25, 12, 49, 46, DateTimeKind.Utc), stat.CreationTimeUtc); Assert.AreEqual(null, stat.DeviceNo); Assert.AreEqual(null, stat.GID); Assert.AreEqual(12, stat.Inode); Assert.AreEqual(new DateTime(2013, 9, 25, 12, 49, 46, DateTimeKind.Utc), stat.LastWriteTimeUtc); Assert.AreEqual(16384, stat.Length); Assert.AreEqual(1, stat.Links); Assert.AreEqual(null, stat.Mode); Assert.AreEqual(null, stat.StatusChangeTimeUtc); Assert.AreEqual(null, stat.UID); error = _fs.Stat("Content/0000000000000000/FFFE07DF/00040000/ContentCache", out stat); Assert.AreEqual(Errno.NoSuchFile, error); error = _fs.Stat("Content/0000000000000000/FFFE07DF/00040000/ContentCache.pkg", out stat); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(new DateTime(2016, 11, 18, 20, 34, 48, DateTimeKind.Utc), stat.AccessTimeUtc); Assert.AreEqual(FileAttributes.None, stat.Attributes); Assert.AreEqual(null, stat.BackupTimeUtc); Assert.AreEqual(6, stat.Blocks); Assert.AreEqual(16384, stat.BlockSize); Assert.AreEqual(new DateTime(2016, 11, 18, 20, 34, 48, DateTimeKind.Utc), stat.CreationTimeUtc); Assert.AreEqual(null, stat.DeviceNo); Assert.AreEqual(null, stat.GID); Assert.AreEqual(18, stat.Inode); Assert.AreEqual(new DateTime(2016, 11, 18, 20, 34, 48, DateTimeKind.Utc), stat.LastWriteTimeUtc); Assert.AreEqual(86016, stat.Length); Assert.AreEqual(1, stat.Links); Assert.AreEqual(null, stat.Mode); Assert.AreEqual(null, stat.StatusChangeTimeUtc); Assert.AreEqual(null, stat.UID); }
public void Stat() { Errno error = _fs.Stat("49470015", out FileEntryInfo stat); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(new DateTime(2007, 3, 6, 15, 8, 44, DateTimeKind.Utc), stat.AccessTimeUtc); Assert.AreEqual(FileAttributes.Directory, stat.Attributes); Assert.AreEqual(null, stat.BackupTimeUtc); Assert.AreEqual(1, stat.Blocks); Assert.AreEqual(16384, stat.BlockSize); Assert.AreEqual(new DateTime(2007, 3, 6, 15, 8, 44, DateTimeKind.Utc), stat.CreationTimeUtc); Assert.AreEqual(null, stat.DeviceNo); Assert.AreEqual(null, stat.GID); Assert.AreEqual(2, stat.Inode); Assert.AreEqual(new DateTime(2007, 3, 6, 15, 8, 44, DateTimeKind.Utc), stat.LastWriteTimeUtc); Assert.AreEqual(16384, stat.Length); Assert.AreEqual(1, stat.Links); Assert.AreEqual(null, stat.Mode); Assert.AreEqual(null, stat.StatusChangeTimeUtc); Assert.AreEqual(null, stat.UID); error = _fs.Stat("49470015/TitleImage", out stat); Assert.AreEqual(Errno.NoSuchFile, error); error = _fs.Stat("49470015/TitleImage.xbx", out stat); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(new DateTime(2013, 5, 14, 12, 50, 8, DateTimeKind.Utc), stat.AccessTimeUtc); Assert.AreEqual(FileAttributes.None, stat.Attributes); Assert.AreEqual(null, stat.BackupTimeUtc); Assert.AreEqual(1, stat.Blocks); Assert.AreEqual(16384, stat.BlockSize); Assert.AreEqual(new DateTime(2013, 5, 14, 12, 50, 8, DateTimeKind.Utc), stat.CreationTimeUtc); Assert.AreEqual(null, stat.DeviceNo); Assert.AreEqual(null, stat.GID); Assert.AreEqual(3, stat.Inode); Assert.AreEqual(new DateTime(2013, 5, 14, 12, 50, 8, DateTimeKind.Utc), stat.LastWriteTimeUtc); Assert.AreEqual(10240, stat.Length); Assert.AreEqual(1, stat.Links); Assert.AreEqual(null, stat.Mode); Assert.AreEqual(null, stat.StatusChangeTimeUtc); Assert.AreEqual(null, stat.UID); }
FilesystemContentsType Files(IReadOnlyFilesystem filesystem) { var contents = new FilesystemContentsType(); Errno ret = filesystem.ReadDir("/", out List <string> dirents); if (ret != Errno.NoError) { return(null); } List <DirectoryType> directories = new List <DirectoryType>(); List <ContentsFileType> files = new List <ContentsFileType>(); foreach (string dirent in dirents) { ret = filesystem.Stat(dirent, out FileEntryInfo stat); if (ret != Errno.NoError) { AaruConsole.DebugWriteLine("Create-Sidecar command", "Cannot stat {0}", dirent); continue; } if (stat.Attributes.HasFlag(FileAttributes.Directory)) { directories.Add(SidecarDirectory(filesystem, "", dirent, stat)); continue; } files.Add(SidecarFile(filesystem, "", dirent, stat)); } if (files.Count > 0) { contents.File = files.OrderBy(f => f.name).ToArray(); } if (directories.Count > 0) { contents.Directory = directories.OrderBy(d => d.name).ToArray(); } return(contents); }
internal static void DoLs(LsOptions options) { DicConsole.DebugWriteLine("Ls command", "--debug={0}", options.Debug); DicConsole.DebugWriteLine("Ls command", "--verbose={0}", options.Verbose); DicConsole.DebugWriteLine("Ls command", "--input={0}", options.InputFile); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(options.InputFile); Dictionary <string, string> parsedOptions = Options.Parse(options.Options); DicConsole.DebugWriteLine("Ls command", "Parsed options:"); foreach (KeyValuePair <string, string> parsedOption in parsedOptions) { DicConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value); } parsedOptions.Add("debug", options.Debug.ToString()); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return; } Encoding encoding = null; if (options.EncodingName != null) { try { encoding = Claunia.Encoding.Encoding.GetEncoding(options.EncodingName); if (options.Verbose) { DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); } } catch (ArgumentException) { DicConsole.ErrorWriteLine("Specified encoding is not supported."); return; } } PluginBase plugins = new PluginBase(); try { IMediaImage imageFormat = ImageFormat.Detect(inputFilter); if (imageFormat == null) { DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); return; } if (options.Verbose) { DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); } else { DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); } try { if (!imageFormat.Open(inputFilter)) { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); return; } DicConsole.DebugWriteLine("Ls command", "Correctly opened image file."); DicConsole.DebugWriteLine("Ls command", "Image without headers is {0} bytes.", imageFormat.Info.ImageSize); DicConsole.DebugWriteLine("Ls command", "Image has {0} sectors.", imageFormat.Info.Sectors); DicConsole.DebugWriteLine("Ls command", "Image identifies disk type as {0}.", imageFormat.Info.MediaType); Core.Statistics.AddMediaFormat(imageFormat.Format); Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); Core.Statistics.AddFilter(inputFilter.Name); } catch (Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); return; } List <Partition> partitions = Core.Partitions.GetAll(imageFormat); Core.Partitions.AddSchemesToStats(partitions); List <string> idPlugins; IReadOnlyFilesystem plugin; Errno error; if (partitions.Count == 0) { DicConsole.DebugWriteLine("Ls command", "No partitions found"); } else { DicConsole.WriteLine("{0} partitions found.", partitions.Count); for (int i = 0; i < partitions.Count; i++) { DicConsole.WriteLine(); DicConsole.WriteLine("Partition {0}:", partitions[i].Sequence); DicConsole.WriteLine("Identifying filesystem on partition"); Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]); if (idPlugins.Count == 0) { DicConsole.WriteLine("Filesystem not identified"); } else if (idPlugins.Count > 1) { DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); foreach (string pluginName in idPlugins) { if (plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) { DicConsole.WriteLine($"As identified by {plugin.Name}."); IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin .GetType() .GetConstructor(Type.EmptyTypes) ?.Invoke(new object[] { }); if (fs == null) { continue; } error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions); if (error == Errno.NoError) { List <string> rootDir = new List <string>(); error = fs.ReadDir("/", out rootDir); if (error == Errno.NoError) { foreach (string entry in rootDir) { DicConsole.WriteLine("{0}", entry); } } else { DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); } Core.Statistics.AddFilesystem(fs.XmlFsType.Type); } else { DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } else { plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); if (plugin == null) { continue; } DicConsole.WriteLine($"Identified by {plugin.Name}."); IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin .GetType().GetConstructor(Type.EmptyTypes) ?.Invoke(new object[] { }); if (fs == null) { continue; } error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions); if (error == Errno.NoError) { List <string> rootDir = new List <string>(); error = fs.ReadDir("/", out rootDir); if (error == Errno.NoError) { foreach (string entry in rootDir) { DicConsole.WriteLine("{0}", entry); } } else { DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); } Core.Statistics.AddFilesystem(fs.XmlFsType.Type); } else { DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } Partition wholePart = new Partition { Name = "Whole device", Length = imageFormat.Info.Sectors, Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize }; Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart); if (idPlugins.Count == 0) { DicConsole.WriteLine("Filesystem not identified"); } else if (idPlugins.Count > 1) { DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); foreach (string pluginName in idPlugins) { if (plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) { DicConsole.WriteLine($"As identified by {plugin.Name}."); IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin .GetType().GetConstructor(Type.EmptyTypes) ?.Invoke(new object[] { }); if (fs == null) { continue; } error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions); if (error == Errno.NoError) { List <string> rootDir = new List <string>(); error = fs.ReadDir("/", out rootDir); if (error == Errno.NoError) { foreach (string entry in rootDir) { DicConsole.WriteLine("{0}", entry); } } else { DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); } Core.Statistics.AddFilesystem(fs.XmlFsType.Type); } else { DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } else { plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); if (plugin != null) { DicConsole.WriteLine($"Identified by {plugin.Name}."); IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin .GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); if (fs != null) { error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions); if (error == Errno.NoError) { List <string> rootDir = new List <string>(); error = fs.ReadDir("/", out rootDir); if (error == Errno.NoError) { foreach (string entry in rootDir) { if (options.Long) { FileEntryInfo stat = new FileEntryInfo(); List <string> xattrs = new List <string>(); error = fs.Stat(entry, out stat); if (error == Errno.NoError) { DicConsole.WriteLine("{0}\t{1}\t{2} bytes\t{3}", stat.CreationTimeUtc, stat.Inode, stat.Length, entry); error = fs.ListXAttr(entry, out xattrs); if (error != Errno.NoError) { continue; } foreach (string xattr in xattrs) { byte[] xattrBuf = new byte[0]; error = fs.GetXattr(entry, xattr, ref xattrBuf); if (error == Errno.NoError) { DicConsole.WriteLine("\t\t{0}\t{1} bytes", xattr, xattrBuf.Length); } } } else { DicConsole.WriteLine("{0}", entry); } } else { DicConsole.WriteLine("{0}", entry); } } } else { DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); } Core.Statistics.AddFilesystem(fs.XmlFsType.Type); } else { DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } } catch (Exception ex) { DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.DebugWriteLine("Ls command", ex.StackTrace); } Core.Statistics.AddCommand("ls"); }
static void ExtractFilesInDir(string path, IReadOnlyFilesystem fs, string volumeName, string outputDir, bool doXattrs) { if (path.StartsWith('/')) { path = path.Substring(1); } Errno error = fs.ReadDir(path, out List <string> directory); if (error != Errno.NoError) { AaruConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); return; } foreach (string entry in directory) { error = fs.Stat(path + "/" + entry, out FileEntryInfo stat); if (error == Errno.NoError) { string outputPath; if (stat.Attributes.HasFlag(FileAttributes.Directory)) { outputPath = Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, path, entry); Directory.CreateDirectory(outputPath); AaruConsole.WriteLine("Created subdirectory at {0}", outputPath); ExtractFilesInDir(path + "/" + entry, fs, volumeName, outputDir, doXattrs); var di = new DirectoryInfo(outputPath); #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body try { if (stat.CreationTimeUtc.HasValue) { di.CreationTimeUtc = stat.CreationTimeUtc.Value; } } catch { // ignored } try { if (stat.LastWriteTimeUtc.HasValue) { di.LastWriteTimeUtc = stat.LastWriteTimeUtc.Value; } } catch { // ignored } try { if (stat.AccessTimeUtc.HasValue) { di.LastAccessTimeUtc = stat.AccessTimeUtc.Value; } } catch { // ignored } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body continue; } FileStream outputFile; if (doXattrs) { error = fs.ListXAttr(path + "/" + entry, out List <string> xattrs); if (error == Errno.NoError) { foreach (string xattr in xattrs) { byte[] xattrBuf = new byte[0]; error = fs.GetXattr(path + "/" + entry, xattr, ref xattrBuf); if (error != Errno.NoError) { continue; } outputPath = Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, path, ".xattrs", xattr); Directory.CreateDirectory(outputPath); outputPath = Path.Combine(outputPath, entry); if (!File.Exists(outputPath)) { outputFile = new FileStream(outputPath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); outputFile.Write(xattrBuf, 0, xattrBuf.Length); outputFile.Close(); var fi = new FileInfo(outputPath); #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body try { if (stat.CreationTimeUtc.HasValue) { fi.CreationTimeUtc = stat.CreationTimeUtc.Value; } } catch { // ignored } try { if (stat.LastWriteTimeUtc.HasValue) { fi.LastWriteTimeUtc = stat.LastWriteTimeUtc.Value; } } catch { // ignored } try { if (stat.AccessTimeUtc.HasValue) { fi.LastAccessTimeUtc = stat.AccessTimeUtc.Value; } } catch { // ignored } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body AaruConsole.WriteLine("Written {0} bytes of xattr {1} from file {2} to {3}", xattrBuf.Length, xattr, entry, outputPath); } else { AaruConsole.ErrorWriteLine("Cannot write xattr {0} for {1}, output exists", xattr, entry); } } } } outputPath = Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, path); Directory.CreateDirectory(outputPath); outputPath = Path.Combine(outputPath, entry); if (!File.Exists(outputPath)) { byte[] outBuf = new byte[0]; error = fs.Read(path + "/" + entry, 0, stat.Length, ref outBuf); if (error == Errno.NoError) { outputFile = new FileStream(outputPath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); outputFile.Write(outBuf, 0, outBuf.Length); outputFile.Close(); var fi = new FileInfo(outputPath); #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body try { if (stat.CreationTimeUtc.HasValue) { fi.CreationTimeUtc = stat.CreationTimeUtc.Value; } } catch { // ignored } try { if (stat.LastWriteTimeUtc.HasValue) { fi.LastWriteTimeUtc = stat.LastWriteTimeUtc.Value; } } catch { // ignored } try { if (stat.AccessTimeUtc.HasValue) { fi.LastAccessTimeUtc = stat.AccessTimeUtc.Value; } } catch { // ignored } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body AaruConsole.WriteLine("Written {0} bytes of file {1} to {2}", outBuf.Length, entry, outputPath); } else { AaruConsole.ErrorWriteLine("Error {0} reading file {1}", error, entry); } } else { AaruConsole.ErrorWriteLine("Cannot write file {0}, output exists", entry); } } else { AaruConsole.ErrorWriteLine("Error reading file {0}", entry); } } }
DirectoryType SidecarDirectory(IReadOnlyFilesystem filesystem, string path, string filename, FileEntryInfo stat) { var directory = new DirectoryType(); if (stat.AccessTimeUtc.HasValue) { directory.accessTime = stat.AccessTimeUtc.Value; directory.accessTimeSpecified = true; } directory.attributes = (ulong)stat.Attributes; if (stat.BackupTimeUtc.HasValue) { directory.backupTime = stat.BackupTimeUtc.Value; directory.backupTimeSpecified = true; } if (stat.CreationTimeUtc.HasValue) { directory.creationTime = stat.CreationTimeUtc.Value; directory.creationTimeSpecified = true; } if (stat.DeviceNo.HasValue) { directory.deviceNumber = stat.DeviceNo.Value; directory.deviceNumberSpecified = true; } directory.inode = stat.Inode; if (stat.LastWriteTimeUtc.HasValue) { directory.lastWriteTime = stat.LastWriteTimeUtc.Value; directory.lastWriteTimeSpecified = true; } directory.links = stat.Links; directory.name = filename; if (stat.GID.HasValue) { directory.posixGroupId = stat.GID.Value; directory.posixGroupIdSpecified = true; } if (stat.Mode.HasValue) { directory.posixMode = stat.Mode.Value; directory.posixModeSpecified = true; } if (stat.UID.HasValue) { directory.posixUserId = stat.UID.Value; directory.posixUserIdSpecified = true; } if (stat.StatusChangeTimeUtc.HasValue) { directory.statusChangeTime = stat.StatusChangeTimeUtc.Value; directory.statusChangeTimeSpecified = true; } Errno ret = filesystem.ReadDir(path + "/" + filename, out List <string> dirents); if (ret != Errno.NoError) { return(null); } List <DirectoryType> directories = new List <DirectoryType>(); List <ContentsFileType> files = new List <ContentsFileType>(); foreach (string dirent in dirents) { ret = filesystem.Stat(path + "/" + filename + "/" + dirent, out FileEntryInfo entryStat); if (ret != Errno.NoError) { AaruConsole.DebugWriteLine("Create-Sidecar command", "Cannot stat {0}", dirent); continue; } if (entryStat.Attributes.HasFlag(FileAttributes.Directory)) { directories.Add(SidecarDirectory(filesystem, path + "/" + filename, dirent, entryStat)); continue; } files.Add(SidecarFile(filesystem, path + "/" + filename, dirent, entryStat)); } if (files.Count > 0) { directory.File = files.OrderBy(f => f.name).ToArray(); } if (directories.Count > 0) { directory.Directory = directories.OrderBy(d => d.name).ToArray(); } return(directory); }
static void ListFilesInDir(string path, IReadOnlyFilesystem fs, bool longFormat) { if (path.StartsWith('/')) { path = path.Substring(1); } AaruConsole.WriteLine(string.IsNullOrEmpty(path) ? "Root directory" : $"Directory: {path}"); Errno error = fs.ReadDir(path, out List <string> directory); if (error != Errno.NoError) { AaruConsole.ErrorWriteLine("Error {0} reading root directory {1}", error.ToString(), path); return; } Dictionary <string, FileEntryInfo> stats = new Dictionary <string, FileEntryInfo>(); foreach (string entry in directory) { fs.Stat(path + "/" + entry, out FileEntryInfo stat); stats.Add(entry, stat); } foreach (KeyValuePair <string, FileEntryInfo> entry in stats.OrderBy(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == false)) { if (longFormat) { if (entry.Value != null) { if (entry.Value.Attributes.HasFlag(FileAttributes.Directory)) { AaruConsole.WriteLine("{0, 10:d} {0, 12:T} {1, -20} {2}", entry.Value.CreationTimeUtc, "<DIR>", entry.Key); } else { AaruConsole.WriteLine("{0, 10:d} {0, 12:T} {1, 6}{2, 14:N0} {3}", entry.Value.CreationTimeUtc, entry.Value.Inode, entry.Value.Length, entry.Key); } error = fs.ListXAttr(path + "/" + entry.Key, out List <string> xattrs); if (error != Errno.NoError) { continue; } foreach (string xattr in xattrs) { byte[] xattrBuf = new byte[0]; error = fs.GetXattr(path + "/" + entry.Key, xattr, ref xattrBuf); if (error == Errno.NoError) { AaruConsole.WriteLine("\t\t{0}\t{1:##,#}", xattr, xattrBuf.Length); } } } else { AaruConsole.WriteLine("{0, 47}{1}", string.Empty, entry.Key); } } else { AaruConsole. WriteLine(entry.Value?.Attributes.HasFlag(FileAttributes.Directory) == true ? "{0}/" : "{0}", entry.Key); } } AaruConsole.WriteLine(); foreach (KeyValuePair <string, FileEntryInfo> subdirectory in stats.Where(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == true)) { ListFilesInDir(path + "/" + subdirectory.Key, fs, longFormat); } }
void TestDirectory(IReadOnlyFilesystem fs, string path, Dictionary <string, FileData> children, string testFile) { Errno ret = fs.ReadDir(path, out List <string> contents); Assert.AreEqual(Errno.NoError, ret, $"Unexpected error {ret} when reading directory \"{path}\" of {testFile}."); if (children.Count == 0 && contents.Count == 0) { return; } if (path == "/") { path = ""; } List <string> expectedNotFound = new List <string>(); foreach (KeyValuePair <string, FileData> child in children) { string childPath = $"{path}/{child.Key}"; ret = fs.Stat(childPath, out FileEntryInfo stat); if (ret == Errno.NoSuchFile || !contents.Contains(child.Key)) { expectedNotFound.Add(child.Key); continue; } contents.Remove(child.Key); Assert.AreEqual(Errno.NoError, ret, $"Unexpected error {ret} retrieving stats for \"{childPath}\" in {testFile}"); stat.Should().BeEquivalentTo(child.Value.Info, $"Wrong info for \"{childPath}\" in {testFile}"); byte[] buffer = new byte[0]; if (child.Value.Info.Attributes.HasFlag(FileAttributes.Directory)) { ret = fs.Read(childPath, 0, 1, ref buffer); Assert.AreEqual(Errno.IsDirectory, ret, $"Got wrong data for directory \"{childPath}\" in {testFile}"); Assert.IsNotNull(child.Value.Children, $"Contents for \"{childPath}\" in {testFile} must be defined in unit test declaration!"); if (child.Value.Children != null) { TestDirectory(fs, childPath, child.Value.Children, testFile); } } else if (child.Value.Info.Attributes.HasFlag(FileAttributes.Symlink)) { ret = fs.ReadLink(childPath, out string link); Assert.AreEqual(Errno.NoError, ret, $"Got wrong data for symbolic link \"{childPath}\" in {testFile}"); Assert.AreEqual(child.Value.LinkTarget, link, $"Invalid target for symbolic link \"{childPath}\" in {testFile}"); } else { // This ensure the buffer does not hang for collection TestFile(fs, childPath, child.Value.MD5, child.Value.Info.Length, testFile); } ret = fs.ListXAttr(childPath, out List <string> xattrs); if (ret == Errno.NotSupported) { Assert.IsNull(child.Value.XattrsWithMd5, $"Defined extended attributes for \"{childPath}\" in {testFile} are not supported by filesystem."); continue; } Assert.AreEqual(Errno.NoError, ret, $"Unexpected error {ret} when listing extended attributes for \"{childPath}\" in {testFile}"); if (xattrs.Count > 0) { Assert.IsNotNull(child.Value.XattrsWithMd5, $"Extended attributes for \"{childPath}\" in {testFile} must be defined in unit test declaration!"); } if (xattrs.Count > 0 || child.Value.XattrsWithMd5?.Count > 0) { TestFileXattrs(fs, childPath, child.Value.XattrsWithMd5, testFile); } } Assert.IsEmpty(expectedNotFound, $"Could not find the children of \"{path}\" in {testFile}: {string.Join(" ", expectedNotFound)}"); Assert.IsEmpty(contents, $"Found the following unexpected children of \"{path}\" in {testFile}: {string.Join(" ", contents)}"); }