From 9c287b211b20f4efc9c7857b285df7a0439f9233 Mon Sep 17 00:00:00 2001 From: emmaus Date: Mon, 5 Nov 2018 10:06:52 +0000 Subject: [PATCH] add support for open fs of internal files --- Ryujinx.HLE/FileSystem/FileSystemProvider.cs | 12 ++ Ryujinx.HLE/FileSystem/IFileSystemProvider.cs | 5 +- Ryujinx.HLE/FileSystem/PFsProvider.cs | 12 ++ Ryujinx.HLE/FileSystem/RomFsProvider.cs | 12 ++ Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs | 1 + .../HOS/Services/FspSrv/IFileSystem.cs | 12 +- .../HOS/Services/FspSrv/IFileSystemProxy.cs | 133 ++++++++++++++---- 7 files changed, 154 insertions(+), 33 deletions(-) diff --git a/Ryujinx.HLE/FileSystem/FileSystemProvider.cs b/Ryujinx.HLE/FileSystem/FileSystemProvider.cs index 1abec88b6a..d3d6b12cd0 100644 --- a/Ryujinx.HLE/FileSystem/FileSystemProvider.cs +++ b/Ryujinx.HLE/FileSystem/FileSystemProvider.cs @@ -252,5 +252,17 @@ namespace Ryujinx.HLE.FileSystem throw new InvalidOperationException($"Path {Path} is not a child directory of {RootPath}"); } + + public bool Disposed { get; private set; } + + protected virtual void Dispose(bool disposing) + { + Disposed = true; + } + + public void Dispose() + { + Dispose(true); + } } } diff --git a/Ryujinx.HLE/FileSystem/IFileSystemProvider.cs b/Ryujinx.HLE/FileSystem/IFileSystemProvider.cs index 70b6c0c835..68c1217e59 100644 --- a/Ryujinx.HLE/FileSystem/IFileSystemProvider.cs +++ b/Ryujinx.HLE/FileSystem/IFileSystemProvider.cs @@ -1,10 +1,13 @@ using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.FspSrv; +using System; namespace Ryujinx.HLE.FileSystem { - interface IFileSystemProvider + interface IFileSystemProvider : IDisposable { + bool Disposed { get; } + long CreateFile(string Name, long Size); long CreateDirectory(string Name); diff --git a/Ryujinx.HLE/FileSystem/PFsProvider.cs b/Ryujinx.HLE/FileSystem/PFsProvider.cs index c4be3341aa..5bdab61576 100644 --- a/Ryujinx.HLE/FileSystem/PFsProvider.cs +++ b/Ryujinx.HLE/FileSystem/PFsProvider.cs @@ -14,6 +14,8 @@ namespace Ryujinx.HLE.FileSystem { private Pfs Pfs; + public bool Disposed { get; private set; } + public PFsProvider(Pfs Pfs) { this.Pfs = Pfs; @@ -143,5 +145,15 @@ namespace Ryujinx.HLE.FileSystem { throw new NotSupportedException(); } + + protected virtual void Dispose(bool disposing) + { + + } + + public void Dispose() + { + Dispose(true); + } } } diff --git a/Ryujinx.HLE/FileSystem/RomFsProvider.cs b/Ryujinx.HLE/FileSystem/RomFsProvider.cs index 8beb8bde53..b8aba0afe7 100644 --- a/Ryujinx.HLE/FileSystem/RomFsProvider.cs +++ b/Ryujinx.HLE/FileSystem/RomFsProvider.cs @@ -14,6 +14,8 @@ namespace Ryujinx.HLE.FileSystem { private Romfs RomFs; + public bool Disposed { get; private set; } + public RomFsProvider(Stream StorageStream) { RomFs = new Romfs(StorageStream); @@ -159,5 +161,15 @@ namespace Ryujinx.HLE.FileSystem { throw new NotSupportedException(); } + + protected virtual void Dispose(bool disposing) + { + Disposed = true; + } + + public void Dispose() + { + Dispose(true); + } } } diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs b/Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs index 804ede2bc3..16ef03be30 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/FsErr.cs @@ -5,6 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv public const int PathDoesNotExist = 1; public const int PathAlreadyExists = 2; public const int PathAlreadyInUse = 7; + public const int PartitionNotFound = 1001; public const int InvalidInput = 6001; } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs index 2097f4e5a4..a9c82aeb0b 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs @@ -9,7 +9,7 @@ using static Ryujinx.HLE.Utilities.StringUtils; namespace Ryujinx.HLE.HOS.Services.FspSrv { - class IFileSystem : IpcService + class IFileSystem : IpcService, IDisposable { private Dictionary m_Commands; @@ -386,5 +386,15 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv OpenPaths.Remove(DirInterface.DirectoryPath); } } + + protected virtual void Dispose(bool disposing) + { + Provider.Dispose(); + } + + public void Dispose() + { + Dispose(true); + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs index 9eabe2d91b..6d047c32eb 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs @@ -85,6 +85,11 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv if (!File.Exists(FullPath)) { + if (FullPath.Contains(".")) + { + return OpenFileSystemFromInternalFile(Context, FullPath); + } + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); } @@ -94,40 +99,11 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv if (Extension == ".nca") { - Nca Nca = new Nca(Context.Device.System.KeySet, FileStream, false); - - NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs); - - if (RomfsSection != null) - { - Stream RomfsStream = Nca.OpenSection(RomfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel); - - IFileSystem NcaFileSystem = new IFileSystem(SwitchPath, new RomFsProvider(RomfsStream)); - - MakeObject(Context, NcaFileSystem); - - return 0; - } + return OpenNcaFs(Context, FullPath, FileStream); } else if (Extension == ".nsp") { - Pfs Nsp = new Pfs(FileStream); - - PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik")); - - if (TicketFile != null) - { - Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile)); - - Context.Device.System.KeySet.TitleKeys[Ticket.RightsId] = - Ticket.GetTitleKey(Context.Device.System.KeySet); - } - - IFileSystem NspFileSystem = new IFileSystem(SwitchPath, new PFsProvider(Nsp)); - - MakeObject(Context, NspFileSystem); - - return 0; + return OpenNsp(Context, FullPath); } return MakeError(ErrorModule.Fs, FsErr.InvalidInput); @@ -264,5 +240,100 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv MakeObject(Context, new IFileSystem(SavePath, FileSystemProvider)); } + + private long OpenNsp(ServiceCtx Context, string PfsPath) + { + FileStream PfsFile = new FileStream(PfsPath, FileMode.Open, FileAccess.Read); + + Pfs Nsp = new Pfs(PfsFile); + + PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik")); + + if (TicketFile != null) + { + Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile)); + + Context.Device.System.KeySet.TitleKeys[Ticket.RightsId] = + Ticket.GetTitleKey(Context.Device.System.KeySet); + } + + IFileSystem NspFileSystem = new IFileSystem(PfsPath, new PFsProvider(Nsp)); + + MakeObject(Context, NspFileSystem); + + return 0; + } + + private long OpenNcaFs(ServiceCtx Context,string NcaPath, Stream NcaStream) + { + Nca Nca = new Nca(Context.Device.System.KeySet, NcaStream, false); + + NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs); + NcaSection PfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0); + + if (RomfsSection != null) + { + Stream RomfsStream = Nca.OpenSection(RomfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel); + + IFileSystem NcaFileSystem = new IFileSystem(NcaPath, new RomFsProvider(RomfsStream)); + + MakeObject(Context, NcaFileSystem); + } + else if(PfsSection !=null) + { + Stream PfsStream = Nca.OpenSection(PfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel); + + Pfs Pfs = new Pfs(PfsStream); + + IFileSystem NcaFileSystem = new IFileSystem(NcaPath, new PFsProvider(Pfs)); + + MakeObject(Context, NcaFileSystem); + } + else + { + return MakeError(ErrorModule.Fs, FsErr.PartitionNotFound); + } + + return 0; + } + + private long OpenFileSystemFromInternalFile(ServiceCtx Context, string FullPath) + { + DirectoryInfo ArchivePath = new DirectoryInfo(FullPath).Parent; + + while (string.IsNullOrWhiteSpace(ArchivePath.Extension)) + { + ArchivePath = ArchivePath.Parent; + } + + if (ArchivePath.Extension == ".nsp" && File.Exists(ArchivePath.FullName)) + { + FileStream PfsFile = new FileStream( + ArchivePath.FullName.TrimEnd(Path.DirectorySeparatorChar), + FileMode.Open, + FileAccess.Read); + + Pfs Nsp = new Pfs(PfsFile); + + PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik")); + + if (TicketFile != null) + { + Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile)); + + Context.Device.System.KeySet.TitleKeys[Ticket.RightsId] = + Ticket.GetTitleKey(Context.Device.System.KeySet); + } + + string Filename = FullPath.Replace(ArchivePath.FullName, string.Empty); + + if (Nsp.FileExists(Filename)) + { + return OpenNcaFs(Context, FullPath, Nsp.OpenFile(Filename)); + } + } + + return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist); + } } } \ No newline at end of file