diff options
| author | Ac_K <Acoustik666@gmail.com> | 2019-09-08 23:33:40 +0200 |
|---|---|---|
| committer | Thomas Guillemard <me@thog.eu> | 2019-09-08 23:33:40 +0200 |
| commit | 1ff89d6482a6ec907bb983c1d2bc473bea546367 (patch) | |
| tree | 9ca3bcb30007abd249419cdd63f8e475bc6059a8 /Ryujinx.HLE/HOS | |
| parent | 9afb8ad485b364e3ecf738b1175c32cce95507bd (diff) | |
Implement basic support of SystemSaveData and Cleanup IFileSystemProxy (#767)
* Implement basic support of SystemSaveData and Cleanup IFileSystemProxy
- Implement `OpenSystemSaveData` as a `IFileSystem` in `SaveHelper`:
On real device, system saves data are stored encrypted, and we can't create an empty system save data for now. That's why if a user put his own dump of system save in `RyuFs\nand\system\save\`, we extract content in associated folder and open it as a `IFileSystem`. If the system save data don't exist, a folder is created.
- Cleanup `IFileSystemProxy` by adding a Helper class.
- Implement `GetSavePath` in `VirtualFileSystem` and remove `GetGameSavePath` in `SaveHelper`.
* remove the forgotten I
* Fix align
Diffstat (limited to 'Ryujinx.HLE/HOS')
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/FspSrv/FileSystemHelper.cs | 144 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs | 184 |
2 files changed, 192 insertions, 136 deletions
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemHelper.cs b/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemHelper.cs new file mode 100644 index 00000000..d2e157f5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/FspSrv/FileSystemHelper.cs @@ -0,0 +1,144 @@ +using LibHac; +using LibHac.Fs; +using LibHac.Fs.NcaUtils; +using Ryujinx.Common; +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.Utilities; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.FspSrv +{ + static class FileSystemHelper + { + public static ResultCode LoadSaveDataFileSystem(ServiceCtx context, bool readOnly, out IFileSystem loadedFileSystem) + { + loadedFileSystem = null; + + SaveSpaceId saveSpaceId = (SaveSpaceId)context.RequestData.ReadInt64(); + ulong titleId = context.RequestData.ReadUInt64(); + UInt128 userId = context.RequestData.ReadStruct<UInt128>(); + long saveId = context.RequestData.ReadInt64(); + SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadByte(); + SaveInfo saveInfo = new SaveInfo(titleId, saveId, saveDataType, saveSpaceId, userId); + string savePath = context.Device.FileSystem.GetSavePath(context, saveInfo); + + try + { + LocalFileSystem fileSystem = new LocalFileSystem(savePath); + LibHac.Fs.IFileSystem saveFileSystem = new DirectorySaveDataFileSystem(fileSystem); + + if (readOnly) + { + saveFileSystem = new ReadOnlyFileSystem(saveFileSystem); + } + + loadedFileSystem = new IFileSystem(saveFileSystem); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + public static ResultCode OpenNsp(ServiceCtx context, string pfsPath, out IFileSystem openedFileSystem) + { + openedFileSystem = null; + + try + { + LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open); + PartitionFileSystem nsp = new PartitionFileSystem(storage); + + ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); + + openedFileSystem = new IFileSystem(nsp); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + public static ResultCode OpenNcaFs(ServiceCtx context, string ncaPath, LibHac.Fs.IStorage ncaStorage, out IFileSystem openedFileSystem) + { + openedFileSystem = null; + + try + { + Nca nca = new Nca(context.Device.System.KeySet, ncaStorage); + + if (!nca.SectionExists(NcaSectionType.Data)) + { + return ResultCode.PartitionNotFound; + } + + LibHac.Fs.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); + + openedFileSystem = new IFileSystem(fileSystem); + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + + return ResultCode.Success; + } + + public static ResultCode OpenFileSystemFromInternalFile(ServiceCtx context, string fullPath, out IFileSystem openedFileSystem) + { + openedFileSystem = null; + + 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); + + try + { + PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage()); + + ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); + + string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); + + if (nsp.FileExists(filename)) + { + return OpenNcaFs(context, fullPath, nsp.OpenFile(filename, OpenMode.Read).AsStorage(), out openedFileSystem); + } + } + catch (HorizonResultException ex) + { + return (ResultCode)ex.ResultValue.Value; + } + } + + return ResultCode.PathDoesNotExist; + } + + public static void ImportTitleKeysFromNsp(LibHac.Fs.IFileSystem nsp, Keyset keySet) + { + foreach (DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik")) + { + Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); + + if (!keySet.TitleKeys.ContainsKey(ticket.RightsId)) + { + keySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(keySet)); + } + } + } + } +}
\ 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 3073d4c7..43f5d647 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs @@ -1,10 +1,8 @@ using LibHac; using LibHac.Fs; using LibHac.Fs.NcaUtils; -using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.Utilities; using System.IO; using static Ryujinx.HLE.FileSystem.VirtualFileSystem; @@ -38,7 +36,14 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv { if (fullPath.Contains(".")) { - return OpenFileSystemFromInternalFile(context, fullPath); + ResultCode result = FileSystemHelper.OpenFileSystemFromInternalFile(context, fullPath, out IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; } return ResultCode.PathDoesNotExist; @@ -49,11 +54,25 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv if (extension == ".nca") { - return OpenNcaFs(context, fullPath, fileStream.AsStorage()); + ResultCode result = FileSystemHelper.OpenNcaFs(context, fullPath, fileStream.AsStorage(), out IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; } else if (extension == ".nsp") { - return OpenNsp(context, fullPath); + ResultCode result = FileSystemHelper.OpenNsp(context, fullPath, out IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; } return ResultCode.InvalidInput; @@ -109,21 +128,42 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv // OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> saveDataFs public ResultCode OpenSaveDataFileSystem(ServiceCtx context) { - return LoadSaveDataFileSystem(context, false); + ResultCode result = FileSystemHelper.LoadSaveDataFileSystem(context, false, out IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; } [Command(52)] // OpenSaveDataFileSystemBySystemSaveDataId(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> systemSaveDataFs public ResultCode OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx context) { - return LoadSaveDataFileSystem(context, false); + ResultCode result = FileSystemHelper.LoadSaveDataFileSystem(context, false, out IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; } [Command(53)] // OpenReadOnlySaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct save_struct) -> object<nn::fssrv::sf::IFileSystem> public ResultCode OpenReadOnlySaveDataFileSystem(ServiceCtx context) { - return LoadSaveDataFileSystem(context, true); + ResultCode result = FileSystemHelper.LoadSaveDataFileSystem(context, true, out IFileSystem fileSystem); + + if (result == ResultCode.Success) + { + MakeObject(context, fileSystem); + } + + return result; } [Command(200)] @@ -227,133 +267,5 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv return ResultCode.Success; } - - public ResultCode LoadSaveDataFileSystem(ServiceCtx context, bool readOnly) - { - SaveSpaceId saveSpaceId = (SaveSpaceId)context.RequestData.ReadInt64(); - - ulong titleId = context.RequestData.ReadUInt64(); - - UInt128 userId = context.RequestData.ReadStruct<UInt128>(); - - long saveId = context.RequestData.ReadInt64(); - SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadByte(); - SaveInfo saveInfo = new SaveInfo(titleId, saveId, saveDataType, userId, saveSpaceId); - string savePath = context.Device.FileSystem.GetGameSavePath(saveInfo, context); - - try - { - LocalFileSystem fileSystem = new LocalFileSystem(savePath); - LibHac.Fs.IFileSystem saveFileSystem = new DirectorySaveDataFileSystem(fileSystem); - - if (readOnly) - { - saveFileSystem = new ReadOnlyFileSystem(saveFileSystem); - } - - MakeObject(context, new IFileSystem(saveFileSystem)); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - private ResultCode OpenNsp(ServiceCtx context, string pfsPath) - { - try - { - LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open); - PartitionFileSystem nsp = new PartitionFileSystem(storage); - - ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); - - IFileSystem nspFileSystem = new IFileSystem(nsp); - - MakeObject(context, nspFileSystem); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - private ResultCode OpenNcaFs(ServiceCtx context, string ncaPath, LibHac.Fs.IStorage ncaStorage) - { - try - { - Nca nca = new Nca(context.Device.System.KeySet, ncaStorage); - - if (!nca.SectionExists(NcaSectionType.Data)) - { - return ResultCode.PartitionNotFound; - } - - LibHac.Fs.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); - - MakeObject(context, new IFileSystem(fileSystem)); - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - - return ResultCode.Success; - } - - private ResultCode 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); - - try - { - PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage()); - - ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); - - string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); - - if (nsp.FileExists(filename)) - { - return OpenNcaFs(context, fullPath, nsp.OpenFile(filename, OpenMode.Read).AsStorage()); - } - } - catch (HorizonResultException ex) - { - return (ResultCode)ex.ResultValue.Value; - } - } - - return ResultCode.PathDoesNotExist; - } - - private void ImportTitleKeysFromNsp(LibHac.Fs.IFileSystem nsp, Keyset keySet) - { - foreach (DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik")) - { - Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); - - if (!keySet.TitleKeys.ContainsKey(ticket.RightsId)) - { - keySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(keySet)); - } - } - } } }
\ No newline at end of file |
