Update to LibHac 0.19.0 (#5831)

* Update to LibHac v0.19.0

- PartitionFileSystem classes now fully match Nintendo's implementation. Current code creating a PartitionFileSystem now need to use the Initialize method.
- Implementing nn::gcsrv and nn::sdmmcsrv now means the FS server now uses that abstraction instead of the old one where we passed in an IDeviceOperator.

* Add GetFileSystemAttribute
This commit is contained in:
Alex Barney 2023-10-22 16:30:46 -07:00 committed by GitHub
parent 33ba170315
commit d773d5152e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 83 additions and 38 deletions

View file

@ -18,7 +18,7 @@
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" /> <PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" /> <PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" /> <PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
<PackageVersion Include="LibHac" Version="0.18.0" /> <PackageVersion Include="LibHac" Version="0.19.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" /> <PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" /> <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" /> <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />

View file

@ -173,7 +173,7 @@ namespace Ryujinx.Ava.Common
string extension = Path.GetExtension(titleFilePath).ToLower(); string extension = Path.GetExtension(titleFilePath).ToLower();
if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci") if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
{ {
PartitionFileSystem pfs; IFileSystem pfs;
if (extension == ".xci") if (extension == ".xci")
{ {
@ -181,7 +181,9 @@ namespace Ryujinx.Ava.Common
} }
else else
{ {
pfs = new PartitionFileSystem(file.AsStorage()); var pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp;
} }
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))

View file

@ -126,7 +126,8 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath); using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage()); PartitionFileSystem partitionFileSystem = new();
partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure();
_virtualFileSystem.ImportTickets(partitionFileSystem); _virtualFileSystem.ImportTickets(partitionFileSystem);
@ -232,7 +233,8 @@ namespace Ryujinx.Ava.UI.ViewModels
using FileStream containerFile = File.OpenRead(path); using FileStream containerFile = File.OpenRead(path);
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage()); PartitionFileSystem partitionFileSystem = new();
partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure();
bool containsDownloadableContent = false; bool containsDownloadableContent = false;
_virtualFileSystem.ImportTickets(partitionFileSystem); _virtualFileSystem.ImportTickets(partitionFileSystem);

View file

@ -170,7 +170,9 @@ namespace Ryujinx.Ava.UI.ViewModels
try 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) if (controlNca != null && patchNca != null)
{ {

View file

@ -238,7 +238,8 @@ namespace Ryujinx.HLE.FileSystem
if (!mergedToContainer) if (!mergedToContainer)
{ {
using FileStream fileStream = File.OpenRead(containerPath); using FileStream fileStream = File.OpenRead(containerPath);
using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage()); using PartitionFileSystem partitionFileSystem = new();
partitionFileSystem.Initialize(fileStream.AsStorage()).ThrowIfFailure();
_virtualFileSystem.ImportTickets(partitionFileSystem); _virtualFileSystem.ImportTickets(partitionFileSystem);
} }
@ -259,16 +260,16 @@ namespace Ryujinx.HLE.FileSystem
{ {
var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read); var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read);
using var ncaFile = new UniqueRef<IFile>(); using var ncaFile = new UniqueRef<IFile>();
PartitionFileSystem pfs;
switch (Path.GetExtension(aoc.ContainerPath)) switch (Path.GetExtension(aoc.ContainerPath))
{ {
case ".xci": case ".xci":
pfs = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure); var xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure);
pfs.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read); xci.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read);
break; break;
case ".nsp": 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); pfs.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read);
break; break;
default: default:

View file

@ -7,6 +7,7 @@ using LibHac.Fs.Shim;
using LibHac.FsSrv; using LibHac.FsSrv;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm; using LibHac.Ncm;
using LibHac.Sdmmc;
using LibHac.Spl; using LibHac.Spl;
using LibHac.Tools.Es; using LibHac.Tools.Es;
using LibHac.Tools.Fs; using LibHac.Tools.Fs;
@ -32,7 +33,7 @@ namespace Ryujinx.HLE.FileSystem
public KeySet KeySet { get; private set; } public KeySet KeySet { get; private set; }
public EmulatedGameCard GameCard { 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; } public ModLoader ModLoader { get; private set; }
private readonly ConcurrentDictionary<ulong, Stream> _romFsByPid; private readonly ConcurrentDictionary<ulong, Stream> _romFsByPid;
@ -198,15 +199,15 @@ namespace Ryujinx.HLE.FileSystem
fsServerObjects.FsCreators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(); fsServerObjects.FsCreators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator();
GameCard = fsServerObjects.GameCard; GameCard = fsServerObjects.GameCard;
SdCard = fsServerObjects.SdCard; SdCard = fsServerObjects.Sdmmc;
SdCard.SetSdCardInsertionStatus(true); SdCard.SetSdCardInserted(true);
var fsServerConfig = new FileSystemServerConfig var fsServerConfig = new FileSystemServerConfig
{ {
DeviceOperator = fsServerObjects.DeviceOperator,
ExternalKeySet = KeySet.ExternalKeySet, ExternalKeySet = KeySet.ExternalKeySet,
FsCreators = fsServerObjects.FsCreators, FsCreators = fsServerObjects.FsCreators,
StorageDeviceManagerFactory = fsServerObjects.StorageDeviceManagerFactory,
RandomGenerator = randomGenerator, RandomGenerator = randomGenerator,
}; };

View file

@ -533,7 +533,9 @@ namespace Ryujinx.HLE.HOS
Logger.Info?.Print(LogClass.ModLoader, "Using replacement ExeFS partition"); 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; return true;
} }

View file

@ -26,7 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
try try
{ {
LocalStorage storage = new(pfsPath, FileAccess.Read, FileMode.Open); LocalStorage storage = new(pfsPath, FileAccess.Read, FileMode.Open);
using SharedRef<LibHac.Fs.Fsa.IFileSystem> nsp = new(new PartitionFileSystem(storage)); var pfs = new PartitionFileSystem();
using SharedRef<LibHac.Fs.Fsa.IFileSystem> nsp = new(pfs);
pfs.Initialize(storage).ThrowIfFailure();
ImportTitleKeysFromNsp(nsp.Get, context.Device.System.KeySet); ImportTitleKeysFromNsp(nsp.Get, context.Device.System.KeySet);
@ -90,7 +92,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
try try
{ {
PartitionFileSystem nsp = new(pfsFile.AsStorage()); PartitionFileSystem nsp = new();
nsp.Initialize(pfsFile.AsStorage()).ThrowIfFailure();
ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet);

View file

@ -1,6 +1,7 @@
using LibHac; using LibHac;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa;
using Path = LibHac.FsSrv.Sf.Path; using Path = LibHac.FsSrv.Sf.Path;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
@ -202,6 +203,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
return (ResultCode)result.Value; 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) protected override void Dispose(bool isDisposing)
{ {
if (isDisposing) if (isDisposing)

View file

@ -1380,7 +1380,10 @@ namespace Ryujinx.HLE.HOS.Services.Fs
[CommandCmif(1016)] [CommandCmif(1016)]
public ResultCode FlushAccessLogOnSdCard(ServiceCtx context) 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)] [CommandCmif(1017)]

View file

@ -20,7 +20,11 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
private static readonly DownloadableContentJsonSerializerContext _contentSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly DownloadableContentJsonSerializerContext _contentSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
private static readonly TitleUpdateMetadataJsonSerializerContext _titleSerializerContext = 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<TMetaData, TFormat, THeader, TEntry>(this PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> partitionFileSystem, Switch device, string path, out string errorMessage)
where TMetaData : PartitionFileSystemMetaCore<TFormat, THeader, TEntry>, new()
where TFormat : IPartitionFileSystemFormat
where THeader : unmanaged, IPartitionFileSystemHeader
where TEntry : unmanaged, IPartitionFileSystemEntry
{ {
errorMessage = null; errorMessage = null;
@ -91,7 +95,8 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
string updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected; string updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected;
if (File.Exists(updatePath)) 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); device.Configuration.VirtualFileSystem.ImportTickets(updatePartitionFileSystem);

View file

@ -69,7 +69,8 @@ namespace Ryujinx.HLE.Loaders.Processes
public bool LoadNsp(string path) public bool LoadNsp(string path)
{ {
FileStream file = new(path, FileMode.Open, FileAccess.Read); 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); (bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, path, out string errorMessage);

View file

@ -1,8 +1,8 @@
using LibHac.Account; using LibHac.Account;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Fs.Shim; using LibHac.Fs.Shim;
using LibHac.FsSystem;
using LibHac.Loader; using LibHac.Loader;
using LibHac.Ncm; using LibHac.Ncm;
using LibHac.Ns; using LibHac.Ns;
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.Loaders.Processes
// TODO: Remove this workaround when ASLR is implemented. // TODO: Remove this workaround when ASLR is implemented.
private const ulong CodeStartOffset = 0x500000UL; 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; ulong applicationId = 0;
int programCount = 0; int programCount = 0;

View file

@ -65,7 +65,7 @@ namespace Ryujinx.Ui.App.Common
if (extension is ".nsp" or ".xci") if (extension is ".nsp" or ".xci")
{ {
PartitionFileSystem pfs; IFileSystem pfs;
if (extension == ".xci") if (extension == ".xci")
{ {
@ -75,7 +75,9 @@ namespace Ryujinx.Ui.App.Common
} }
else else
{ {
pfs = new PartitionFileSystem(file.AsStorage()); var pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp;
} }
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))

View file

@ -174,7 +174,7 @@ namespace Ryujinx.Ui.App.Common
{ {
try try
{ {
PartitionFileSystem pfs; IFileSystem pfs;
bool isExeFs = false; bool isExeFs = false;
@ -186,7 +186,9 @@ namespace Ryujinx.Ui.App.Common
} }
else 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. // 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; bool hasMainNca = false;
@ -500,7 +502,7 @@ namespace Ryujinx.Ui.App.Common
ApplicationCountUpdated?.Invoke(null, e); 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); (_, _, Nca controlNca) = GetGameData(_virtualFileSystem, pfs, 0);
@ -563,7 +565,7 @@ namespace Ryujinx.Ui.App.Common
{ {
try try
{ {
PartitionFileSystem pfs; IFileSystem pfs;
bool isExeFs = false; bool isExeFs = false;
@ -575,7 +577,9 @@ namespace Ryujinx.Ui.App.Common
} }
else else
{ {
pfs = new PartitionFileSystem(file.AsStorage()); var pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp;
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*")) foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*"))
{ {
@ -827,7 +831,7 @@ namespace Ryujinx.Ui.App.Common
return false; 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 mainNca = null;
Nca patchNca = null; Nca patchNca = null;
@ -931,7 +935,8 @@ namespace Ryujinx.Ui.App.Common
if (File.Exists(updatePath)) if (File.Exists(updatePath))
{ {
FileStream file = new(updatePath, FileMode.Open, FileAccess.Read); 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); return GetGameUpdateDataFromPartition(fileSystem, nsp, titleIdBase.ToString("x16"), programIndex);
} }

View file

@ -211,7 +211,7 @@ namespace Ryujinx.Ui.Widgets
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") || (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") ||
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci")) (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci"))
{ {
PartitionFileSystem pfs; IFileSystem pfs;
if (System.IO.Path.GetExtension(_titleFilePath) == ".xci") if (System.IO.Path.GetExtension(_titleFilePath) == ".xci")
{ {
@ -221,7 +221,9 @@ namespace Ryujinx.Ui.Widgets
} }
else else
{ {
pfs = new PartitionFileSystem(file.AsStorage()); var pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp;
} }
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))

View file

@ -88,7 +88,8 @@ namespace Ryujinx.Ui.Windows
using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath); using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath);
PartitionFileSystem pfs = new(containerFile.AsStorage()); PartitionFileSystem pfs = new();
pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure();
_virtualFileSystem.ImportTickets(pfs); _virtualFileSystem.ImportTickets(pfs);
@ -153,7 +154,8 @@ namespace Ryujinx.Ui.Windows
using FileStream containerFile = File.OpenRead(containerPath); using FileStream containerFile = File.OpenRead(containerPath);
PartitionFileSystem pfs = new(containerFile.AsStorage()); PartitionFileSystem pfs = new();
pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure();
bool containsDlc = false; bool containsDlc = false;
_virtualFileSystem.ImportTickets(pfs); _virtualFileSystem.ImportTickets(pfs);

View file

@ -90,7 +90,8 @@ namespace Ryujinx.Ui.Windows
{ {
using FileStream file = new(path, FileMode.Open, FileAccess.Read); using FileStream file = new(path, FileMode.Open, FileAccess.Read);
PartitionFileSystem nsp = new(file.AsStorage()); PartitionFileSystem nsp = new();
nsp.Initialize(file.AsStorage()).ThrowIfFailure();
try try
{ {