aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Fs
diff options
context:
space:
mode:
authorAlex Barney <thealexbarney@gmail.com>2020-01-05 04:49:44 -0700
committerThog <me@thog.eu>2020-01-05 12:49:44 +0100
commit63b24b4af2804f173764c98586a19c39db04ad4d (patch)
tree7994f00e4bc06edc430004a7caa1bdf0231b2668 /Ryujinx.HLE/HOS/Services/Fs
parente0e12b1672e49ab5810bf88bf8274990605ed67a (diff)
Rename "RyuFs" directory to "Ryujinx" and use the same savedata system the Switch uses (#801)
* Use savedata FS commands from LibHac * Add EnsureSaveData. Use ApplicationControlProperty struct * Add a function to migrate to the new directory layout * LibHac update * Change backup structure * Don't create UI files in the save path * Update RyuFs paths * Add GetProgramIndexForAccessLog Ryujinx only runs one program at a time, so always return values reflecting that * Load control NCA when loading from an NSP * Skip over UI stats when exiting * Set TitleName and TitleId in more cases. Fix TitleID naming style * Completely comment out GUI play stats code * rebase * Update LibHac * Update LibHac * Revert UI changes * Do migration automatically at startup * Rename RyuFs directory to Ryujinx * Update RyuFs text * Store savedata paths in the GUI * Make "Open Save Directory" work * Use a dummy NACP in EnsureSaveData if one is not loaded * Remove manual migration button * Respond to feedback * Don't read the installer config to get a version string * Delete nuget.config * Exclude 'sdcard' and 'bis' during migration Co-authored-by: Thog <thog@protonmail.com>
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Fs')
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs52
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs222
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs31
3 files changed, 225 insertions, 80 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
index 2b0f06dd..1dd5fb86 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
@@ -3,54 +3,12 @@ using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using LibHac.Spl;
-using Ryujinx.Common;
-using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.Utilities;
using System.IO;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{
static class FileSystemProxyHelper
{
- 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);
-
- Result result = DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem dirFileSystem, fileSystem);
- if (result.IsFailure())
- {
- return (ResultCode)result.Value;
- }
-
- LibHac.Fs.IFileSystem saveFileSystem = dirFileSystem;
-
- 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;
@@ -154,5 +112,15 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
}
}
}
+
+ public static Result ReadFsPath(out FsPath path, ServiceCtx context, int index = 0)
+ {
+ long position = context.Request.SendBuff[index].Position;
+ long size = context.Request.SendBuff[index].Size;
+
+ byte[] pathBytes = context.Memory.ReadBytes(position, size);
+
+ return FsPath.FromSpan(out path, pathBytes);
+ }
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
index 38111019..60f4a3f4 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
@@ -3,13 +3,14 @@ using LibHac.Fs;
using LibHac.FsService;
using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
+using LibHac.Ncm;
+using Ryujinx.Common;
using Ryujinx.Common.Logging;
-using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy;
using System.IO;
-using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
using static Ryujinx.HLE.Utilities.StringUtils;
+using StorageId = Ryujinx.HLE.FileSystem.StorageId;
namespace Ryujinx.HLE.HOS.Services.Fs
{
@@ -90,29 +91,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenBisFileSystem(nn::fssrv::sf::Partition partitionID, buffer<bytes<0x301>, 0x19, 0x301>) -> object<nn::fssrv::sf::IFileSystem> Bis
public ResultCode OpenBisFileSystem(ServiceCtx context)
{
- int bisPartitionId = context.RequestData.ReadInt32();
- string partitionString = ReadUtf8String(context);
- string bisPartitionPath = string.Empty;
+ BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32();
- switch (bisPartitionId)
- {
- case 29:
- bisPartitionPath = SafeNandPath;
- break;
- case 30:
- case 31:
- bisPartitionPath = SystemNandPath;
- break;
- case 32:
- bisPartitionPath = UserNandPath;
- break;
- default:
- return ResultCode.InvalidInput;
- }
+ Result rc = FileSystemProxyHelper.ReadFsPath(out FsPath path, context);
+ if (rc.IsFailure()) return (ResultCode)rc.Value;
- string fullPath = context.Device.FileSystem.GetFullPartitionPath(bisPartitionPath);
-
- LocalFileSystem fileSystem = new LocalFileSystem(fullPath);
+ rc = _baseFileSystemProxy.OpenBisFileSystem(out LibHac.Fs.IFileSystem fileSystem, ref path, bisPartitionId);
+ if (rc.IsFailure()) return (ResultCode)rc.Value;
MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem));
@@ -123,15 +108,69 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenSdCardFileSystem() -> object<nn::fssrv::sf::IFileSystem>
public ResultCode OpenSdCardFileSystem(ServiceCtx context)
{
- string sdCardPath = context.Device.FileSystem.GetSdCardPath();
-
- LocalFileSystem fileSystem = new LocalFileSystem(sdCardPath);
+ Result rc = _baseFileSystemProxy.OpenSdCardFileSystem(out LibHac.Fs.IFileSystem fileSystem);
+ if (rc.IsFailure()) return (ResultCode)rc.Value;
MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem));
return ResultCode.Success;
}
+ [Command(21)]
+ public ResultCode DeleteSaveDataFileSystem(ServiceCtx context)
+ {
+ ulong saveDataId = context.RequestData.ReadUInt64();
+
+ Result result = _baseFileSystemProxy.DeleteSaveDataFileSystem(saveDataId);
+
+ return (ResultCode)result.Value;
+ }
+
+ [Command(22)]
+ public ResultCode CreateSaveDataFileSystem(ServiceCtx context)
+ {
+ SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
+ SaveDataCreateInfo createInfo = context.RequestData.ReadStruct<SaveDataCreateInfo>();
+ SaveMetaCreateInfo metaCreateInfo = context.RequestData.ReadStruct<SaveMetaCreateInfo>();
+
+ Result result = _baseFileSystemProxy.CreateSaveDataFileSystem(ref attribute, ref createInfo, ref metaCreateInfo);
+
+ return (ResultCode)result.Value;
+ }
+
+ [Command(23)]
+ public ResultCode CreateSaveDataFileSystemBySystemSaveDataId(ServiceCtx context)
+ {
+ SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
+ SaveDataCreateInfo createInfo = context.RequestData.ReadStruct<SaveDataCreateInfo>();
+
+ Result result = _baseFileSystemProxy.CreateSaveDataFileSystemBySystemSaveDataId(ref attribute, ref createInfo);
+
+ return (ResultCode)result.Value;
+ }
+
+ [Command(25)]
+ public ResultCode DeleteSaveDataFileSystemBySaveDataSpaceId(ServiceCtx context)
+ {
+ SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
+ ulong saveDataId = context.RequestData.ReadUInt64();
+
+ Result result = _baseFileSystemProxy.DeleteSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId);
+
+ return (ResultCode)result.Value;
+ }
+
+ [Command(28)]
+ public ResultCode DeleteSaveDataFileSystemBySaveDataAttribute(ServiceCtx context)
+ {
+ SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
+ SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
+
+ Result result = _baseFileSystemProxy.DeleteSaveDataFileSystemBySaveDataAttribute(spaceId, ref attribute);
+
+ return (ResultCode)result.Value;
+ }
+
[Command(30)]
// OpenGameCardStorage(u32, u32) -> object<nn::fssrv::sf::IStorage>
public ResultCode OpenGameCardStorage(ServiceCtx context)
@@ -149,46 +188,141 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return (ResultCode)result.Value;
}
+ [Command(35)]
+ public ResultCode CreateSaveDataFileSystemWithHashSalt(ServiceCtx context)
+ {
+ SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
+ SaveDataCreateInfo createInfo = context.RequestData.ReadStruct<SaveDataCreateInfo>();
+ SaveMetaCreateInfo metaCreateInfo = context.RequestData.ReadStruct<SaveMetaCreateInfo>();
+ HashSalt hashSalt = context.RequestData.ReadStruct<HashSalt>();
+
+ Result result = _baseFileSystemProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref createInfo, ref metaCreateInfo, ref hashSalt);
+
+ return (ResultCode)result.Value;
+ }
+
[Command(51)]
// OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> saveDataFs
public ResultCode OpenSaveDataFileSystem(ServiceCtx context)
{
- ResultCode result = FileSystemProxyHelper.LoadSaveDataFileSystem(context, false, out FileSystemProxy.IFileSystem fileSystem);
+ SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
+ SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
+
+ if (attribute.TitleId == TitleId.Zero)
+ {
+ attribute.TitleId = new TitleId(context.Process.TitleId);
+ }
- if (result == ResultCode.Success)
+ Result result = _baseFileSystemProxy.OpenSaveDataFileSystem(out LibHac.Fs.IFileSystem fileSystem, spaceId, ref attribute);
+
+ if (result.IsSuccess())
{
- MakeObject(context, fileSystem);
+ MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem));
}
- return result;
+ return (ResultCode)result.Value;
}
[Command(52)]
// OpenSaveDataFileSystemBySystemSaveDataId(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> systemSaveDataFs
public ResultCode OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx context)
{
- ResultCode result = FileSystemProxyHelper.LoadSaveDataFileSystem(context, false, out FileSystemProxy.IFileSystem fileSystem);
+ SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
+ SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
+
+ Result result = _baseFileSystemProxy.OpenSaveDataFileSystemBySystemSaveDataId(out LibHac.Fs.IFileSystem fileSystem, spaceId, ref attribute);
- if (result == ResultCode.Success)
+ if (result.IsSuccess())
{
- MakeObject(context, fileSystem);
+ MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem));
}
- return result;
+ return (ResultCode)result.Value;
}
[Command(53)]
// OpenReadOnlySaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct save_struct) -> object<nn::fssrv::sf::IFileSystem>
public ResultCode OpenReadOnlySaveDataFileSystem(ServiceCtx context)
{
- ResultCode result = FileSystemProxyHelper.LoadSaveDataFileSystem(context, true, out FileSystemProxy.IFileSystem fileSystem);
+ SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
+ SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
+
+ if (attribute.TitleId == TitleId.Zero)
+ {
+ attribute.TitleId = new TitleId(context.Process.TitleId);
+ }
+
+ Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.IFileSystem fileSystem, spaceId, ref attribute);
+
+ if (result.IsSuccess())
+ {
+ MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem));
+ }
+
+ return (ResultCode)result.Value;
+ }
+
+ [Command(60)]
+ public ResultCode OpenSaveDataInfoReader(ServiceCtx context)
+ {
+ Result result = _baseFileSystemProxy.OpenSaveDataInfoReader(out LibHac.FsService.ISaveDataInfoReader infoReader);
- if (result == ResultCode.Success)
+ if (result.IsSuccess())
{
- MakeObject(context, fileSystem);
+ MakeObject(context, new ISaveDataInfoReader(infoReader));
}
- return result;
+ return (ResultCode)result.Value;
+ }
+
+ [Command(61)]
+ public ResultCode OpenSaveDataInfoReaderBySaveDataSpaceId(ServiceCtx context)
+ {
+ SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadByte();
+
+ Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderBySaveDataSpaceId(out LibHac.FsService.ISaveDataInfoReader infoReader, spaceId);
+
+ if (result.IsSuccess())
+ {
+ MakeObject(context, new ISaveDataInfoReader(infoReader));
+ }
+
+ return (ResultCode)result.Value;
+ }
+
+ [Command(67)]
+ public ResultCode FindSaveDataWithFilter(ServiceCtx context)
+ {
+ SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
+ SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>();
+
+ long bufferPosition = context.Request.ReceiveBuff[0].Position;
+ long bufferLen = context.Request.ReceiveBuff[0].Size;
+
+ byte[] infoBuffer = new byte[bufferLen];
+
+ Result result = _baseFileSystemProxy.FindSaveDataWithFilter(out long count, infoBuffer, spaceId, ref filter);
+
+ context.Memory.WriteBytes(bufferPosition, infoBuffer);
+ context.ResponseData.Write(count);
+
+ return (ResultCode)result.Value;
+ }
+
+ [Command(68)]
+ public ResultCode OpenSaveDataInfoReaderWithFilter(ServiceCtx context)
+ {
+ SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
+ SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>();
+
+ Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderWithFilter(out LibHac.FsService.ISaveDataInfoReader infoReader, spaceId, ref filter);
+
+ if (result.IsSuccess())
+ {
+ MakeObject(context, new ISaveDataInfoReader(infoReader));
+ }
+
+ return (ResultCode)result.Value;
}
[Command(200)]
@@ -306,5 +440,17 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return ResultCode.Success;
}
+
+ [Command(1011)]
+ public ResultCode GetProgramIndexForAccessLog(ServiceCtx context)
+ {
+ int programIndex = 0;
+ int programCount = 1;
+
+ context.ResponseData.Write(programIndex);
+ context.ResponseData.Write(programCount);
+
+ return ResultCode.Success;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs b/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs
new file mode 100644
index 00000000..3d5ae8e2
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Fs/ISaveDataInfoReader.cs
@@ -0,0 +1,31 @@
+using LibHac;
+
+namespace Ryujinx.HLE.HOS.Services.Fs
+{
+ class ISaveDataInfoReader : IpcService
+ {
+ private LibHac.FsService.ISaveDataInfoReader _baseReader;
+
+ public ISaveDataInfoReader(LibHac.FsService.ISaveDataInfoReader baseReader)
+ {
+ _baseReader = baseReader;
+ }
+
+ [Command(0)]
+ // ReadSaveDataInfo() -> (u64, buffer<unknown, 6>)
+ public ResultCode ReadSaveDataInfo(ServiceCtx context)
+ {
+ long bufferPosition = context.Request.ReceiveBuff[0].Position;
+ long bufferLen = context.Request.ReceiveBuff[0].Size;
+
+ byte[] infoBuffer = new byte[bufferLen];
+
+ Result result = _baseReader.ReadSaveDataInfo(out long readCount, infoBuffer);
+
+ context.Memory.WriteBytes(bufferPosition, infoBuffer);
+ context.ResponseData.Write(readCount);
+
+ return (ResultCode)result.Value;
+ }
+ }
+}