diff --git a/Directory.Packages.props b/Directory.Packages.props
index 6fdaafddc..4fd079af6 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -18,7 +18,7 @@
-
+
diff --git a/src/Ryujinx.Ava/Common/ApplicationHelper.cs b/src/Ryujinx.Ava/Common/ApplicationHelper.cs
index b8cd06f3d..91ca8f4d5 100644
--- a/src/Ryujinx.Ava/Common/ApplicationHelper.cs
+++ b/src/Ryujinx.Ava/Common/ApplicationHelper.cs
@@ -173,7 +173,7 @@ namespace Ryujinx.Ava.Common
string extension = Path.GetExtension(titleFilePath).ToLower();
if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
{
- PartitionFileSystem pfs;
+ IFileSystem pfs;
if (extension == ".xci")
{
@@ -181,7 +181,9 @@ namespace Ryujinx.Ava.Common
}
else
{
- pfs = new PartitionFileSystem(file.AsStorage());
+ var pfsTemp = new PartitionFileSystem();
+ pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
+ pfs = pfsTemp;
}
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
diff --git a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs
index b88bd3d9c..cdecae77d 100644
--- a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs
+++ b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs
@@ -126,7 +126,8 @@ namespace Ryujinx.Ava.UI.ViewModels
{
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
- PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
+ PartitionFileSystem partitionFileSystem = new();
+ partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure();
_virtualFileSystem.ImportTickets(partitionFileSystem);
@@ -232,7 +233,8 @@ namespace Ryujinx.Ava.UI.ViewModels
using FileStream containerFile = File.OpenRead(path);
- PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
+ PartitionFileSystem partitionFileSystem = new();
+ partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure();
bool containsDownloadableContent = false;
_virtualFileSystem.ImportTickets(partitionFileSystem);
diff --git a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs
index dd0b92a51..5090a8c70 100644
--- a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs
+++ b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs
@@ -170,7 +170,9 @@ namespace Ryujinx.Ava.UI.ViewModels
try
{
- (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, new PartitionFileSystem(file.AsStorage()), TitleId.ToString("x16"), 0);
+ var pfs = new PartitionFileSystem();
+ pfs.Initialize(file.AsStorage()).ThrowIfFailure();
+ (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, pfs, TitleId.ToString("x16"), 0);
if (controlNca != null && patchNca != null)
{
diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs
index 646808e78..8ade34a8b 100644
--- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs
+++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs
@@ -238,7 +238,8 @@ namespace Ryujinx.HLE.FileSystem
if (!mergedToContainer)
{
using FileStream fileStream = File.OpenRead(containerPath);
- using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage());
+ using PartitionFileSystem partitionFileSystem = new();
+ partitionFileSystem.Initialize(fileStream.AsStorage()).ThrowIfFailure();
_virtualFileSystem.ImportTickets(partitionFileSystem);
}
@@ -259,16 +260,16 @@ namespace Ryujinx.HLE.FileSystem
{
var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read);
using var ncaFile = new UniqueRef();
- PartitionFileSystem pfs;
switch (Path.GetExtension(aoc.ContainerPath))
{
case ".xci":
- pfs = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure);
- pfs.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read);
+ var xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure);
+ xci.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read);
break;
case ".nsp":
- pfs = new PartitionFileSystem(file.AsStorage());
+ var pfs = new PartitionFileSystem();
+ pfs.Initialize(file.AsStorage());
pfs.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read);
break;
default:
diff --git a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs
index 807020c60..eaf481dd7 100644
--- a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs
+++ b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs
@@ -7,6 +7,7 @@ using LibHac.Fs.Shim;
using LibHac.FsSrv;
using LibHac.FsSystem;
using LibHac.Ncm;
+using LibHac.Sdmmc;
using LibHac.Spl;
using LibHac.Tools.Es;
using LibHac.Tools.Fs;
@@ -32,7 +33,7 @@ namespace Ryujinx.HLE.FileSystem
public KeySet KeySet { get; private set; }
public EmulatedGameCard GameCard { get; private set; }
- public EmulatedSdCard SdCard { get; private set; }
+ public SdmmcApi SdCard { get; private set; }
public ModLoader ModLoader { get; private set; }
private readonly ConcurrentDictionary _romFsByPid;
@@ -198,15 +199,15 @@ namespace Ryujinx.HLE.FileSystem
fsServerObjects.FsCreators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator();
GameCard = fsServerObjects.GameCard;
- SdCard = fsServerObjects.SdCard;
+ SdCard = fsServerObjects.Sdmmc;
- SdCard.SetSdCardInsertionStatus(true);
+ SdCard.SetSdCardInserted(true);
var fsServerConfig = new FileSystemServerConfig
{
- DeviceOperator = fsServerObjects.DeviceOperator,
ExternalKeySet = KeySet.ExternalKeySet,
FsCreators = fsServerObjects.FsCreators,
+ StorageDeviceManagerFactory = fsServerObjects.StorageDeviceManagerFactory,
RandomGenerator = randomGenerator,
};
diff --git a/src/Ryujinx.HLE/HOS/ModLoader.cs b/src/Ryujinx.HLE/HOS/ModLoader.cs
index 6706006c3..834bc0595 100644
--- a/src/Ryujinx.HLE/HOS/ModLoader.cs
+++ b/src/Ryujinx.HLE/HOS/ModLoader.cs
@@ -533,7 +533,9 @@ namespace Ryujinx.HLE.HOS
Logger.Info?.Print(LogClass.ModLoader, "Using replacement ExeFS partition");
- exefs = new PartitionFileSystem(mods.ExefsContainers[0].Path.OpenRead().AsStorage());
+ var pfs = new PartitionFileSystem();
+ pfs.Initialize(mods.ExefsContainers[0].Path.OpenRead().AsStorage()).ThrowIfFailure();
+ exefs = pfs;
return true;
}
diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
index 599025e3b..1ef52a00d 100644
--- a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
@@ -26,7 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
try
{
LocalStorage storage = new(pfsPath, FileAccess.Read, FileMode.Open);
- using SharedRef nsp = new(new PartitionFileSystem(storage));
+ var pfs = new PartitionFileSystem();
+ using SharedRef nsp = new(pfs);
+ pfs.Initialize(storage).ThrowIfFailure();
ImportTitleKeysFromNsp(nsp.Get, context.Device.System.KeySet);
@@ -90,7 +92,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
try
{
- PartitionFileSystem nsp = new(pfsFile.AsStorage());
+ PartitionFileSystem nsp = new();
+ nsp.Initialize(pfsFile.AsStorage()).ThrowIfFailure();
ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet);
diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs
index 4c5c56240..66020d57b 100644
--- a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs
@@ -1,6 +1,7 @@
using LibHac;
using LibHac.Common;
using LibHac.Fs;
+using LibHac.Fs.Fsa;
using Path = LibHac.FsSrv.Sf.Path;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
@@ -202,6 +203,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
return (ResultCode)result.Value;
}
+ [CommandCmif(16)]
+ public ResultCode GetFileSystemAttribute(ServiceCtx context)
+ {
+ Result result = _fileSystem.Get.GetFileSystemAttribute(out FileSystemAttribute attribute);
+
+ context.ResponseData.Write(SpanHelpers.AsReadOnlyByteSpan(in attribute));
+
+ return (ResultCode)result.Value;
+ }
+
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
index 644e1a17a..24dd1e9be 100644
--- a/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
@@ -1380,7 +1380,10 @@ namespace Ryujinx.HLE.HOS.Services.Fs
[CommandCmif(1016)]
public ResultCode FlushAccessLogOnSdCard(ServiceCtx context)
{
- return (ResultCode)_baseFileSystemProxy.Get.FlushAccessLogOnSdCard().Value;
+ // Logging the access log to the SD card isn't implemented, meaning this function will be a no-op since
+ // there's nothing to flush. Return success until it's implemented.
+ // return (ResultCode)_baseFileSystemProxy.Get.FlushAccessLogOnSdCard().Value;
+ return ResultCode.Success;
}
[CommandCmif(1017)]
diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs
index 6de99131e..50f7d5853 100644
--- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs
+++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs
@@ -20,7 +20,11 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
private static readonly DownloadableContentJsonSerializerContext _contentSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
private static readonly TitleUpdateMetadataJsonSerializerContext _titleSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
- internal static (bool, ProcessResult) TryLoad(this PartitionFileSystem partitionFileSystem, Switch device, string path, out string errorMessage)
+ internal static (bool, ProcessResult) TryLoad(this PartitionFileSystemCore partitionFileSystem, Switch device, string path, out string errorMessage)
+ where TMetaData : PartitionFileSystemMetaCore, new()
+ where TFormat : IPartitionFileSystemFormat
+ where THeader : unmanaged, IPartitionFileSystemHeader
+ where TEntry : unmanaged, IPartitionFileSystemEntry
{
errorMessage = null;
@@ -91,7 +95,8 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
string updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected;
if (File.Exists(updatePath))
{
- PartitionFileSystem updatePartitionFileSystem = new(new FileStream(updatePath, FileMode.Open, FileAccess.Read).AsStorage());
+ PartitionFileSystem updatePartitionFileSystem = new();
+ updatePartitionFileSystem.Initialize(new FileStream(updatePath, FileMode.Open, FileAccess.Read).AsStorage()).ThrowIfFailure();
device.Configuration.VirtualFileSystem.ImportTickets(updatePartitionFileSystem);
diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs
index 51cbb6f99..220b868db 100644
--- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs
+++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs
@@ -69,7 +69,8 @@ namespace Ryujinx.HLE.Loaders.Processes
public bool LoadNsp(string path)
{
FileStream file = new(path, FileMode.Open, FileAccess.Read);
- PartitionFileSystem partitionFileSystem = new(file.AsStorage());
+ PartitionFileSystem partitionFileSystem = new();
+ partitionFileSystem.Initialize(file.AsStorage()).ThrowIfFailure();
(bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, path, out string errorMessage);
diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs
index 292a5c122..c229b1742 100644
--- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs
+++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs
@@ -1,8 +1,8 @@
using LibHac.Account;
using LibHac.Common;
using LibHac.Fs;
+using LibHac.Fs.Fsa;
using LibHac.Fs.Shim;
-using LibHac.FsSystem;
using LibHac.Loader;
using LibHac.Ncm;
using LibHac.Ns;
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.Loaders.Processes
// TODO: Remove this workaround when ASLR is implemented.
private const ulong CodeStartOffset = 0x500000UL;
- public static LibHac.Result RegisterProgramMapInfo(Switch device, PartitionFileSystem partitionFileSystem)
+ public static LibHac.Result RegisterProgramMapInfo(Switch device, IFileSystem partitionFileSystem)
{
ulong applicationId = 0;
int programCount = 0;
diff --git a/src/Ryujinx.Ui.Common/App/ApplicationData.cs b/src/Ryujinx.Ui.Common/App/ApplicationData.cs
index e6130bdac..1be883ee1 100644
--- a/src/Ryujinx.Ui.Common/App/ApplicationData.cs
+++ b/src/Ryujinx.Ui.Common/App/ApplicationData.cs
@@ -65,7 +65,7 @@ namespace Ryujinx.Ui.App.Common
if (extension is ".nsp" or ".xci")
{
- PartitionFileSystem pfs;
+ IFileSystem pfs;
if (extension == ".xci")
{
@@ -75,7 +75,9 @@ namespace Ryujinx.Ui.App.Common
}
else
{
- pfs = new PartitionFileSystem(file.AsStorage());
+ var pfsTemp = new PartitionFileSystem();
+ pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
+ pfs = pfsTemp;
}
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
diff --git a/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs b/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs
index 36b2b727d..2f688126a 100644
--- a/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs
+++ b/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs
@@ -174,7 +174,7 @@ namespace Ryujinx.Ui.App.Common
{
try
{
- PartitionFileSystem pfs;
+ IFileSystem pfs;
bool isExeFs = false;
@@ -186,7 +186,9 @@ namespace Ryujinx.Ui.App.Common
}
else
{
- pfs = new PartitionFileSystem(file.AsStorage());
+ var pfsTemp = new PartitionFileSystem();
+ pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
+ pfs = pfsTemp;
// If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application.
bool hasMainNca = false;
@@ -500,7 +502,7 @@ namespace Ryujinx.Ui.App.Common
ApplicationCountUpdated?.Invoke(null, e);
}
- private void GetControlFsAndTitleId(PartitionFileSystem pfs, out IFileSystem controlFs, out string titleId)
+ private void GetControlFsAndTitleId(IFileSystem pfs, out IFileSystem controlFs, out string titleId)
{
(_, _, Nca controlNca) = GetGameData(_virtualFileSystem, pfs, 0);
@@ -563,7 +565,7 @@ namespace Ryujinx.Ui.App.Common
{
try
{
- PartitionFileSystem pfs;
+ IFileSystem pfs;
bool isExeFs = false;
@@ -575,7 +577,9 @@ namespace Ryujinx.Ui.App.Common
}
else
{
- pfs = new PartitionFileSystem(file.AsStorage());
+ var pfsTemp = new PartitionFileSystem();
+ pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
+ pfs = pfsTemp;
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*"))
{
@@ -827,7 +831,7 @@ namespace Ryujinx.Ui.App.Common
return false;
}
- public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex)
+ public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, IFileSystem pfs, int programIndex)
{
Nca mainNca = null;
Nca patchNca = null;
@@ -931,7 +935,8 @@ namespace Ryujinx.Ui.App.Common
if (File.Exists(updatePath))
{
FileStream file = new(updatePath, FileMode.Open, FileAccess.Read);
- PartitionFileSystem nsp = new(file.AsStorage());
+ PartitionFileSystem nsp = new();
+ nsp.Initialize(file.AsStorage()).ThrowIfFailure();
return GetGameUpdateDataFromPartition(fileSystem, nsp, titleIdBase.ToString("x16"), programIndex);
}
diff --git a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs b/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs
index ea60421f8..5af181b08 100644
--- a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs
+++ b/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs
@@ -211,7 +211,7 @@ namespace Ryujinx.Ui.Widgets
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") ||
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci"))
{
- PartitionFileSystem pfs;
+ IFileSystem pfs;
if (System.IO.Path.GetExtension(_titleFilePath) == ".xci")
{
@@ -221,7 +221,9 @@ namespace Ryujinx.Ui.Widgets
}
else
{
- pfs = new PartitionFileSystem(file.AsStorage());
+ var pfsTemp = new PartitionFileSystem();
+ pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
+ pfs = pfsTemp;
}
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
diff --git a/src/Ryujinx/Ui/Windows/DlcWindow.cs b/src/Ryujinx/Ui/Windows/DlcWindow.cs
index 74aef00f4..9f7179467 100644
--- a/src/Ryujinx/Ui/Windows/DlcWindow.cs
+++ b/src/Ryujinx/Ui/Windows/DlcWindow.cs
@@ -88,7 +88,8 @@ namespace Ryujinx.Ui.Windows
using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath);
- PartitionFileSystem pfs = new(containerFile.AsStorage());
+ PartitionFileSystem pfs = new();
+ pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure();
_virtualFileSystem.ImportTickets(pfs);
@@ -153,7 +154,8 @@ namespace Ryujinx.Ui.Windows
using FileStream containerFile = File.OpenRead(containerPath);
- PartitionFileSystem pfs = new(containerFile.AsStorage());
+ PartitionFileSystem pfs = new();
+ pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure();
bool containsDlc = false;
_virtualFileSystem.ImportTickets(pfs);
diff --git a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs b/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs
index 044f7e95a..51918eeab 100644
--- a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs
+++ b/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs
@@ -90,7 +90,8 @@ namespace Ryujinx.Ui.Windows
{
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
- PartitionFileSystem nsp = new(file.AsStorage());
+ PartitionFileSystem nsp = new();
+ nsp.Initialize(file.AsStorage()).ThrowIfFailure();
try
{