From c35d9ba043459f412aaf6467819809f69ee64a9f Mon Sep 17 00:00:00 2001 From: emmaus Date: Thu, 23 Aug 2018 19:12:22 +0000 Subject: [PATCH] initial save path implementation --- Ryujinx.HLE/FileSystem/Save.cs | 14 ++++ Ryujinx.HLE/FileSystem/SaveDataType.cs | 12 +++ Ryujinx.HLE/FileSystem/SaveHelper.cs | 44 ++++++++++ Ryujinx.HLE/FileSystem/SaveSpaceId.cs | 10 +++ .../{ => FileSystem}/VirtualFileSystem.cs | 8 +- .../HOS/Services/FspSrv/IFileSystemProxy.cs | 82 +++++++++++++++++-- Ryujinx.HLE/HOS/SystemState/UserId.cs | 14 ++++ Ryujinx.HLE/Switch.cs | 1 + 8 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 Ryujinx.HLE/FileSystem/Save.cs create mode 100644 Ryujinx.HLE/FileSystem/SaveDataType.cs create mode 100644 Ryujinx.HLE/FileSystem/SaveHelper.cs create mode 100644 Ryujinx.HLE/FileSystem/SaveSpaceId.cs rename Ryujinx.HLE/{ => FileSystem}/VirtualFileSystem.cs (91%) diff --git a/Ryujinx.HLE/FileSystem/Save.cs b/Ryujinx.HLE/FileSystem/Save.cs new file mode 100644 index 0000000000..1bf0cddc99 --- /dev/null +++ b/Ryujinx.HLE/FileSystem/Save.cs @@ -0,0 +1,14 @@ +using Ryujinx.HLE.HOS.SystemState; + +namespace Ryujinx.HLE.FileSystem +{ + struct Save + { + public long TitleId { get; set; } + public long SaveID { get; set; } + public UserId UserID { get; set; } + + public SaveDataType SaveDataType { get; set; } + public SaveSpaceId SaveSpaceId { get; set; } + } +} diff --git a/Ryujinx.HLE/FileSystem/SaveDataType.cs b/Ryujinx.HLE/FileSystem/SaveDataType.cs new file mode 100644 index 0000000000..2314263ca9 --- /dev/null +++ b/Ryujinx.HLE/FileSystem/SaveDataType.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.FileSystem +{ + enum SaveDataType + { + SystemSaveData, + SaveData, + BcatDeliveryCacheStorage, + DeviceSaveData, + TemporaryStorage, + CacheStorage + } +} diff --git a/Ryujinx.HLE/FileSystem/SaveHelper.cs b/Ryujinx.HLE/FileSystem/SaveHelper.cs new file mode 100644 index 0000000000..9b4a02144c --- /dev/null +++ b/Ryujinx.HLE/FileSystem/SaveHelper.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using Ryujinx.HLE.HOS; + +namespace Ryujinx.HLE.FileSystem +{ + static class SaveHelper + { + public static string GetSavePath(Save SaveMetaData, ServiceCtx Context) + { + string BasePartitionPath = "nand"; + long CurrentTitleId = SaveMetaData.TitleId; + + switch (SaveMetaData.SaveSpaceId) + { + case SaveSpaceId.NandUser: + BasePartitionPath = Path.Combine(BasePartitionPath, "user"); + break; + case SaveSpaceId.NandSystem: + BasePartitionPath = Path.Combine(BasePartitionPath, "system"); + break; + case SaveSpaceId.SdCard: + BasePartitionPath = Path.Combine("sdmc", "Nintendo"); + break; + } + + BasePartitionPath = Path.Combine(BasePartitionPath, "save"); + + if (SaveMetaData.TitleId == 0 && SaveMetaData.SaveDataType == SaveDataType.SaveData) + { + CurrentTitleId = Context.Process.MetaData.ACI0.TitleId; + } + + string SavePath = Path.Combine(BasePartitionPath, + SaveMetaData.SaveID.ToString("X16"), + SaveMetaData.UserID.ToString(), + SaveMetaData.SaveDataType == SaveDataType.SaveData ? CurrentTitleId.ToString("X16") : string.Empty); + + return SavePath; + } + } +} diff --git a/Ryujinx.HLE/FileSystem/SaveSpaceId.cs b/Ryujinx.HLE/FileSystem/SaveSpaceId.cs new file mode 100644 index 0000000000..d51922df1a --- /dev/null +++ b/Ryujinx.HLE/FileSystem/SaveSpaceId.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.FileSystem +{ + enum SaveSpaceId + { + NandSystem, + NandUser, + SdCard, + TemporaryStorage + } +} diff --git a/Ryujinx.HLE/VirtualFileSystem.cs b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs similarity index 91% rename from Ryujinx.HLE/VirtualFileSystem.cs rename to Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index 133538f93a..38209da3ad 100644 --- a/Ryujinx.HLE/VirtualFileSystem.cs +++ b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -1,7 +1,8 @@ using System; using System.IO; +using Ryujinx.HLE.HOS; -namespace Ryujinx.HLE +namespace Ryujinx.HLE.FileSystem { class VirtualFileSystem : IDisposable { @@ -50,7 +51,10 @@ namespace Ryujinx.HLE public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath); - public string GetGameSavesPath() => MakeDirAndGetFullPath(NandPath); + public string GetNandPath() => MakeDirAndGetFullPath(NandPath); + + public string GetGameSavesPath(Save SaveMetaData, ServiceCtx Context) + => MakeDirAndGetFullPath(SaveHelper.GetSavePath(SaveMetaData, Context)); public string GetSystemPath() => MakeDirAndGetFullPath(SystemPath); diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs index 14edcc759e..743171fafa 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.Logging; using System.Collections.Generic; +using Ryujinx.HLE.FileSystem; namespace Ryujinx.HLE.HOS.Services.FspSrv { @@ -14,13 +15,14 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv { m_Commands = new Dictionary() { - { 1, SetCurrentProcess }, - { 18, OpenSdCardFileSystem }, - { 22, CreateSaveDataFileSystem }, - { 51, OpenSaveDataFileSystem }, - { 200, OpenDataStorageByCurrentProcess }, - { 203, OpenPatchDataStorageByCurrentProcess }, - { 1005, GetGlobalAccessLogMode } + { 1, SetCurrentProcess }, + { 18, OpenSdCardFileSystem }, + { 22, CreateSaveDataFileSystem }, + { 51, OpenSaveDataFileSystem }, + { 52, OpenSaveDataFileSystemBySystemSaveDataId }, + { 200, OpenDataStorageByCurrentProcess }, + { 203, OpenPatchDataStorageByCurrentProcess }, + { 1005, GetGlobalAccessLogMode } }; } @@ -38,14 +40,49 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv public long CreateSaveDataFileSystem(ServiceCtx Context) { - Context.Device.Log.PrintStub(LogClass.ServiceFs, "Stubbed."); + long TitleId = Context.RequestData.ReadInt64(); + long UserIdHigh = Context.RequestData.ReadInt64(); + long UserIdLow = Context.RequestData.ReadInt64(); + long SaveId = Context.RequestData.ReadInt64(); + + SaveDataType Type = (SaveDataType)Context.RequestData.ReadByte(); + + Save SaveInfo = new Save() + { + TitleId = TitleId, + UserID = new SystemState.UserId(UserIdLow, UserIdHigh), + SaveID = SaveId, + SaveDataType = Type + }; + + switch (SaveInfo.SaveDataType) + { + case SaveDataType.SaveData: + SaveInfo.SaveSpaceId = SaveSpaceId.NandUser; + break; + case SaveDataType.SystemSaveData: + SaveInfo.SaveSpaceId = SaveSpaceId.NandSystem; + break; + } + + byte[] SaveCreateStruct = Context.RequestData.ReadBytes(0x40); + byte[] Input = Context.RequestData.ReadBytes(0x10); + + Context.Device.FileSystem.GetGameSavesPath(SaveInfo, Context); return 0; } public long OpenSaveDataFileSystem(ServiceCtx Context) { - MakeObject(Context, new IFileSystem(Context.Device.FileSystem.GetGameSavesPath())); + LoadSaveDataFileSystem(Context); + + return 0; + } + + public long OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx Context) + { + LoadSaveDataFileSystem(Context); return 0; } @@ -70,5 +107,32 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv return 0; } + + public void LoadSaveDataFileSystem(ServiceCtx Context) + { + byte id = Context.RequestData.ReadByte(); + SaveSpaceId SaveSpaceId = (SaveSpaceId)id; + + int Unknown = Context.RequestData.ReadInt32(); + + long TitleId = Context.RequestData.ReadInt64(); + byte[] UserId = Context.RequestData.ReadBytes(0x10); + long SaveId = Context.RequestData.ReadInt64(); + + byte type = Context.RequestData.ReadByte(); + SaveDataType Type = (SaveDataType)type; + + Save SaveInfo = new Save() + { + TitleId = TitleId, + UserID = new SystemState.UserId(UserId), + SaveID = SaveId, + SaveDataType = Type + }; + + SaveInfo.SaveSpaceId = SaveSpaceId; + + MakeObject(Context, new IFileSystem(Context.Device.FileSystem.GetGameSavesPath(SaveInfo, Context))); + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/SystemState/UserId.cs b/Ryujinx.HLE/HOS/SystemState/UserId.cs index 1e7c53dd00..ff40bd7ef9 100644 --- a/Ryujinx.HLE/HOS/SystemState/UserId.cs +++ b/Ryujinx.HLE/HOS/SystemState/UserId.cs @@ -43,6 +43,20 @@ namespace Ryujinx.HLE.HOS.SystemState this.Bytes = Bytes; } + public UserId(byte[] UserIdBytes) + { + Bytes = UserIdBytes; + + UserIdHex = string.Empty; + + foreach (byte Byte in Bytes) + { + UserIdHex += Byte.ToString("X2"); + } + + this.Bytes = Bytes; + } + public UserId(string UserIdHex) { if (UserIdHex == null || UserIdHex.Length != 32 || !UserIdHex.All("0123456789abcdefABCDEF".Contains)) diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 090aae111e..70bd7060ec 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -1,6 +1,7 @@ using Ryujinx.Audio; using Ryujinx.Graphics; using Ryujinx.Graphics.Gal; +using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.Input; using Ryujinx.HLE.Logging;