string BuildFile(IReadOnlyFilesystem fs, string path, long length) { byte[] buffer = new byte[length]; fs.Read(path, 0, length, ref buffer); return(Md5Context.Data(buffer, out _)); }
void TestFile(IReadOnlyFilesystem fs, string path, string md5, long length, string testFile) { byte[] buffer = new byte[length]; Errno ret = fs.Read(path, 0, length, ref buffer); Assert.AreEqual(Errno.NoError, ret, $"Unexpected error {ret} when reading \"{path}\" in {testFile}"); string data = Md5Context.Data(buffer, out _); Assert.AreEqual(md5, data, $"Got MD5 {data} for \"{path}\" in {testFile} but expected {md5}"); }
public void Read() { byte[] buffer = new byte[0]; Errno error = _fs.Read("Content/0000000000000000/FFFE07DF/00040000", 0, 0, ref buffer); Assert.AreEqual(Errno.IsDirectory, error); error = _fs.Read("Content/0000000000000000/FFFE07DF/00040000/ContentCache", 0, 0, ref buffer); Assert.AreEqual(Errno.NoSuchFile, error); error = _fs.Read("Content/0000000000000000/FFFE07DF/00040000/ContentCache.pkg", 0, 0, ref buffer); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(0, buffer.Length); Assert.AreEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", Sha256Context.Data(buffer, out _)); error = _fs.Read("Content/0000000000000000/FFFE07DF/00040000/ContentCache.pkg", 1, 16, ref buffer); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(16, buffer.Length); Assert.AreEqual("f73a941675b8df16b0fc908f242c3c51382c5b159e709e0f9ffc1e5aac35f77d", Sha256Context.Data(buffer, out _)); error = _fs.Read("Content/0000000000000000/FFFE07DF/00040000/ContentCache.pkg", 248, 131072, ref buffer); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(85768, buffer.Length); Assert.AreEqual("19caf1365e1b7d5446ca0c2518d15e94c3ab0faaf2f8f3b31c9e1656dff57bd9", Sha256Context.Data(buffer, out _)); error = _fs.Read("Content/0000000000000000/FFFE07DF/00040000/ContentCache.pkg", 131072, 0, ref buffer); Assert.AreEqual(Errno.InvalidArgument, error); }
public void Read() { byte[] buffer = new byte[0]; Errno error = _fs.Read("49470015", 0, 0, ref buffer); Assert.AreEqual(Errno.IsDirectory, error); error = _fs.Read("49470015/TitleImage", 0, 0, ref buffer); Assert.AreEqual(Errno.NoSuchFile, error); error = _fs.Read("49470015/7AC2FE88C908/savedata.dat", 0, 0, ref buffer); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(0, buffer.Length); Assert.AreEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", Sha256Context.Data(buffer, out _)); error = _fs.Read("49470015/7AC2FE88C908/savedata.dat", 1, 16, ref buffer); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(16, buffer.Length); Assert.AreEqual("ff82559d2d0c610ac25b78dcb53a8312e32b56192044deb1f01540581bd54e80", Sha256Context.Data(buffer, out _)); error = _fs.Read("49470015/7AC2FE88C908/savedata.dat", 248, 131072, ref buffer); Assert.AreEqual(Errno.NoError, error); Assert.AreEqual(61996, buffer.Length); Assert.AreEqual("2eb0d62a96ad28473ce0dd67052efdfae31f371992e1d8309beeeff6f2b46a59", Sha256Context.Data(buffer, out _)); error = _fs.Read("49470015/7AC2FE88C908/savedata.dat", 131072, 0, ref buffer); Assert.AreEqual(Errno.InvalidArgument, error); }
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); } } }
ContentsFileType SidecarFile(IReadOnlyFilesystem filesystem, string path, string filename, FileEntryInfo stat) { var file = new ContentsFileType(); var fileChkWorker = new Checksum(); if (stat.AccessTimeUtc.HasValue) { file.accessTime = stat.AccessTimeUtc.Value; file.accessTimeSpecified = true; } file.attributes = (ulong)stat.Attributes; if (stat.BackupTimeUtc.HasValue) { file.backupTime = stat.BackupTimeUtc.Value; file.backupTimeSpecified = true; } if (stat.CreationTimeUtc.HasValue) { file.creationTime = stat.CreationTimeUtc.Value; file.creationTimeSpecified = true; } if (stat.DeviceNo.HasValue) { file.deviceNumber = stat.DeviceNo.Value; file.deviceNumberSpecified = true; } file.inode = stat.Inode; if (stat.LastWriteTimeUtc.HasValue) { file.lastWriteTime = stat.LastWriteTimeUtc.Value; file.lastWriteTimeSpecified = true; } file.length = (ulong)stat.Length; file.links = stat.Links; file.name = filename; if (stat.GID.HasValue) { file.posixGroupId = stat.GID.Value; file.posixGroupIdSpecified = true; } if (stat.Mode.HasValue) { file.posixMode = stat.Mode.Value; file.posixModeSpecified = true; } if (stat.UID.HasValue) { file.posixUserId = stat.UID.Value; file.posixUserIdSpecified = true; } if (stat.StatusChangeTimeUtc.HasValue) { file.statusChangeTime = stat.StatusChangeTimeUtc.Value; file.statusChangeTimeSpecified = true; } byte[] data = new byte[0]; if (stat.Length > 0) { long position = 0; UpdateStatus($"Hashing file {path}/{filename}..."); InitProgress2(); while (position < stat.Length - 1048576) { if (_aborted) { return(file); } data = new byte[1048576]; filesystem.Read(path + "/" + filename, position, 1048576, ref data); UpdateProgress2("Hashing file byte {0} of {1}", position, stat.Length); fileChkWorker.Update(data); position += 1048576; } data = new byte[stat.Length - position]; filesystem.Read(path + "/" + filename, position, stat.Length - position, ref data); UpdateProgress2("Hashing file byte {0} of {1}", position, stat.Length); fileChkWorker.Update(data); EndProgress(); file.Checksums = fileChkWorker.End().ToArray(); } else { file.Checksums = _emptyChecksums; } Errno ret = filesystem.ListXAttr(path + "/" + filename, out List <string> xattrs); if (ret != Errno.NoError) { return(file); } List <ExtendedAttributeType> xattrTypes = new List <ExtendedAttributeType>(); foreach (string xattr in xattrs) { ret = filesystem.GetXattr(path + "/" + filename, xattr, ref data); if (ret != Errno.NoError) { continue; } var xattrChkWorker = new Checksum(); xattrChkWorker.Update(data); xattrTypes.Add(new ExtendedAttributeType { Checksums = xattrChkWorker.End().ToArray(), length = (ulong)data.Length, name = xattr }); } if (xattrTypes.Count > 0) { file.ExtendedAttributes = xattrTypes.OrderBy(x => x.name).ToArray(); } return(file); }
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)}"); }