Update to LibHac 0.6.0 (#792)

* Update to LibHac 0.6.0

* Create an IFileSystemProxy object from LibHac

* Rename rc -> result

* Alignment and spacing

* Result formatting

* Spacing

* Sort usings
This commit is contained in:
Alex Barney 2019-10-17 01:17:44 -05:00 committed by Ac_K
parent c0fe6cdca0
commit 8a8ea4c8c0
18 changed files with 353 additions and 404 deletions

View file

@ -1,5 +1,5 @@
using LibHac.Fs; using LibHac.FsSystem;
using LibHac.Fs.NcaUtils; using LibHac.FsSystem.NcaUtils;
using Ryujinx.HLE.HOS.Services.Time; using Ryujinx.HLE.HOS.Services.Time;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System; using System;
@ -16,13 +16,13 @@ namespace Ryujinx.HLE.FileSystem.Content
private Dictionary<string, long> _sharedFontTitleDictionary; private Dictionary<string, long> _sharedFontTitleDictionary;
private Dictionary<string, string> _sharedFontFilenameDictionary; private Dictionary<string, string> _sharedFontFilenameDictionary;
private SortedDictionary<(ulong, ContentType), string> _contentDictionary; private SortedDictionary<(ulong, NcaContentType), string> _contentDictionary;
private Switch _device; private Switch _device;
public ContentManager(Switch device) public ContentManager(Switch device)
{ {
_contentDictionary = new SortedDictionary<(ulong, ContentType), string>(); _contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>(); _locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
_sharedFontTitleDictionary = new Dictionary<string, long> _sharedFontTitleDictionary = new Dictionary<string, long>
@ -50,7 +50,7 @@ namespace Ryujinx.HLE.FileSystem.Content
public void LoadEntries() public void LoadEntries()
{ {
_contentDictionary = new SortedDictionary<(ulong, ContentType), string>(); _contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
foreach (StorageId storageId in Enum.GetValues(typeof(StorageId))) foreach (StorageId storageId in Enum.GetValues(typeof(StorageId)))
{ {
@ -146,7 +146,7 @@ namespace Ryujinx.HLE.FileSystem.Content
TimeManager.Instance.InitializeTimeZone(_device); TimeManager.Instance.InitializeTimeZone(_device);
} }
public void ClearEntry(long titleId, ContentType contentType, StorageId storageId) public void ClearEntry(long titleId, NcaContentType contentType, StorageId storageId)
{ {
RemoveLocationEntry(titleId, contentType, storageId); RemoveLocationEntry(titleId, contentType, storageId);
} }
@ -173,10 +173,10 @@ namespace Ryujinx.HLE.FileSystem.Content
{ {
if (_contentDictionary.ContainsValue(ncaId)) if (_contentDictionary.ContainsValue(ncaId))
{ {
var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId); var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId);
long titleId = (long)content.Key.Item1; long titleId = (long)content.Key.Item1;
ContentType contentType = content.Key.Item2; NcaContentType contentType = content.Key.Item2;
StorageId storage = GetInstalledStorage(titleId, contentType, storageId); StorageId storage = GetInstalledStorage(titleId, contentType, storageId);
return storage == storageId; return storage == storageId;
} }
@ -184,7 +184,7 @@ namespace Ryujinx.HLE.FileSystem.Content
return false; return false;
} }
public UInt128 GetInstalledNcaId(long titleId, ContentType contentType) public UInt128 GetInstalledNcaId(long titleId, NcaContentType contentType)
{ {
if (_contentDictionary.ContainsKey(((ulong)titleId,contentType))) if (_contentDictionary.ContainsKey(((ulong)titleId,contentType)))
{ {
@ -194,7 +194,7 @@ namespace Ryujinx.HLE.FileSystem.Content
return new UInt128(); return new UInt128();
} }
public StorageId GetInstalledStorage(long titleId, ContentType contentType, StorageId storageId) public StorageId GetInstalledStorage(long titleId, NcaContentType contentType, StorageId storageId)
{ {
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
@ -202,7 +202,7 @@ namespace Ryujinx.HLE.FileSystem.Content
LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None; LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None;
} }
public string GetInstalledContentPath(long titleId, StorageId storageId, ContentType contentType) public string GetInstalledContentPath(long titleId, StorageId storageId, NcaContentType contentType)
{ {
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
@ -226,7 +226,7 @@ namespace Ryujinx.HLE.FileSystem.Content
AddLocationEntry(newEntry, storageId); AddLocationEntry(newEntry, storageId);
} }
private bool VerifyContentType(LocationEntry locationEntry, ContentType contentType) private bool VerifyContentType(LocationEntry locationEntry, NcaContentType contentType)
{ {
if (locationEntry.ContentPath == null) if (locationEntry.ContentPath == null)
{ {
@ -273,7 +273,7 @@ namespace Ryujinx.HLE.FileSystem.Content
} }
} }
private void RemoveLocationEntry(long titleId, ContentType contentType, StorageId storageId) private void RemoveLocationEntry(long titleId, NcaContentType contentType, StorageId storageId)
{ {
LinkedList<LocationEntry> locationList = null; LinkedList<LocationEntry> locationList = null;
@ -304,7 +304,7 @@ namespace Ryujinx.HLE.FileSystem.Content
return _sharedFontFilenameDictionary.TryGetValue(fontName, out filename); return _sharedFontFilenameDictionary.TryGetValue(fontName, out filename);
} }
private LocationEntry GetLocation(long titleId, ContentType contentType, StorageId storageId) private LocationEntry GetLocation(long titleId, NcaContentType contentType, StorageId storageId)
{ {
LinkedList<LocationEntry> locationList = _locationEntries[storageId]; LinkedList<LocationEntry> locationList = _locationEntries[storageId];

View file

@ -1,15 +1,15 @@
using LibHac.Fs.NcaUtils; using LibHac.FsSystem.NcaUtils;
namespace Ryujinx.HLE.FileSystem.Content namespace Ryujinx.HLE.FileSystem.Content
{ {
public struct LocationEntry public struct LocationEntry
{ {
public string ContentPath { get; private set; } public string ContentPath { get; private set; }
public int Flag { get; private set; } public int Flag { get; private set; }
public long TitleId { get; private set; } public long TitleId { get; private set; }
public ContentType ContentType { get; private set; } public NcaContentType ContentType { get; private set; }
public LocationEntry(string contentPath, int flag, long titleId, ContentType contentType) public LocationEntry(string contentPath, int flag, long titleId, NcaContentType contentType)
{ {
ContentPath = contentPath; ContentPath = contentPath;
Flag = flag; Flag = flag;

View file

@ -1,4 +1,5 @@
using LibHac.Fs; using LibHac.Fs;
using LibHac.FsSystem;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using System.IO; using System.IO;
@ -21,9 +22,9 @@ namespace Ryujinx.HLE.FileSystem
using (LocalStorage systemSaveData = new LocalStorage(savePath, FileAccess.Read, FileMode.Open)) using (LocalStorage systemSaveData = new LocalStorage(savePath, FileAccess.Read, FileMode.Open))
{ {
IFileSystem saveFs = new LibHac.Fs.Save.SaveDataFileSystem(context.Device.System.KeySet, systemSaveData, IntegrityCheckLevel.None, false); IFileSystem saveFs = new LibHac.FsSystem.Save.SaveDataFileSystem(context.Device.System.KeySet, systemSaveData, IntegrityCheckLevel.None, false);
saveFs.CopyFileSystem(outputFolder); saveFs.CopyDirectory(outputFolder, "/", "/");
} }
File.Delete(savePath); File.Delete(savePath);

View file

@ -1,5 +1,6 @@
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.NcaUtils; using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
@ -55,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Font
if (contentManager.TryGetFontTitle(name, out long fontTitle) && if (contentManager.TryGetFontTitle(name, out long fontTitle) &&
contentManager.TryGetFontFilename(name, out string fontFilename)) contentManager.TryGetFontFilename(name, out string fontFilename))
{ {
string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, ContentType.Data); string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, NcaContentType.Data);
string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath); string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(fontPath)) if (!string.IsNullOrWhiteSpace(fontPath))
@ -66,9 +67,10 @@ namespace Ryujinx.HLE.HOS.Font
{ {
Nca nca = new Nca(_device.System.KeySet, ncaFileStream); Nca nca = new Nca(_device.System.KeySet, ncaFileStream);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
Stream fontFile = romfs.OpenFile(fontFilename, OpenMode.Read).AsStream();
data = DecryptFont(fontFile); romfs.OpenFile(out IFile fontFile, "/" + fontFilename, OpenMode.Read).ThrowIfFailure();
data = DecryptFont(fontFile.AsStream());
} }
FontInfo info = new FontInfo((int)fontOffset, data.Length); FontInfo info = new FontInfo((int)fontOffset, data.Length);

View file

@ -1,6 +1,9 @@
using LibHac; using LibHac;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.NcaUtils; using LibHac.FsService;
using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using LibHac.Spl;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Font; using Ryujinx.HLE.HOS.Font;
@ -116,6 +119,9 @@ namespace Ryujinx.HLE.HOS
internal long HidBaseAddress { get; private set; } internal long HidBaseAddress { get; private set; }
internal FileSystemServer FsServer { get; private set; }
internal EmulatedGameCard GameCard { get; private set; }
public Horizon(Switch device) public Horizon(Switch device)
{ {
ControlData = new Nacp(); ControlData = new Nacp();
@ -228,6 +234,21 @@ namespace Ryujinx.HLE.HOS
// FIXME: TimeZone shoud be init here but it's actually done in ContentManager // FIXME: TimeZone shoud be init here but it's actually done in ContentManager
TimeServiceManager.Instance.SetupEphemeralNetworkSystemClock(); TimeServiceManager.Instance.SetupEphemeralNetworkSystemClock();
LocalFileSystem serverBaseFs = new LocalFileSystem(device.FileSystem.GetBasePath());
DefaultFsServerObjects fsServerObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(serverBaseFs, KeySet);
GameCard = fsServerObjects.GameCard;
FileSystemServerConfig fsServerConfig = new FileSystemServerConfig
{
FsCreators = fsServerObjects.FsCreators,
DeviceOperator = fsServerObjects.DeviceOperator,
ExternalKeySet = KeySet.ExternalKeySet
};
FsServer = new FileSystemServer(fsServerConfig);
} }
public void LoadCart(string exeFsDir, string romFsFile = null) public void LoadCart(string exeFsDir, string romFsFile = null)
@ -283,25 +304,31 @@ namespace Ryujinx.HLE.HOS
XciPartition securePartition = xci.OpenPartition(XciPartitionType.Secure); XciPartition securePartition = xci.OpenPartition(XciPartitionType.Secure);
foreach (DirectoryEntry ticketEntry in securePartition.EnumerateEntries("*.tik")) foreach (DirectoryEntryEx ticketEntry in securePartition.EnumerateEntries("/", "*.tik"))
{ {
Ticket ticket = new Ticket(securePartition.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); Result result = securePartition.OpenFile(out IFile ticketFile, ticketEntry.FullPath, OpenMode.Read);
if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId)) if (result.IsSuccess())
{ {
KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet)); Ticket ticket = new Ticket(ticketFile.AsStream());
KeySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(KeySet)));
} }
} }
foreach (DirectoryEntry fileEntry in securePartition.EnumerateEntries("*.nca")) foreach (DirectoryEntryEx fileEntry in securePartition.EnumerateEntries("/", "*.nca"))
{ {
IStorage ncaStorage = securePartition.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage(); Result result = securePartition.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read);
if (result.IsFailure())
Nca nca = new Nca(KeySet, ncaStorage);
if (nca.Header.ContentType == ContentType.Program)
{ {
int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, ContentType.Program); continue;
}
Nca nca = new Nca(KeySet, ncaFile.AsStorage());
if (nca.Header.ContentType == NcaContentType.Program)
{
int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
if (nca.Header.GetFsHeader(dataIndex).IsPatchSection()) if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
{ {
@ -312,7 +339,7 @@ namespace Ryujinx.HLE.HOS
mainNca = nca; mainNca = nca;
} }
} }
else if (nca.Header.ContentType == ContentType.Control) else if (nca.Header.ContentType == NcaContentType.Control)
{ {
controlNca = nca; controlNca = nca;
} }
@ -335,11 +362,14 @@ namespace Ryujinx.HLE.HOS
{ {
IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel); IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
IFile controlFile = controlFs.OpenFile("/control.nacp", OpenMode.Read); Result result = controlFs.OpenFile(out IFile controlFile, "/control.nacp", OpenMode.Read);
ControlData = new Nacp(controlFile.AsStream()); if (result.IsSuccess())
{
ControlData = new Nacp(controlFile.AsStream());
TitleName = CurrentTitle = ControlData.Descriptions[(int)State.DesiredTitleLanguage].Title; TitleName = CurrentTitle = ControlData.Descriptions[(int) State.DesiredTitleLanguage].Title;
}
} }
public void LoadNca(string ncaFile) public void LoadNca(string ncaFile)
@ -357,13 +387,15 @@ namespace Ryujinx.HLE.HOS
PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());
foreach (DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik")) foreach (DirectoryEntryEx ticketEntry in nsp.EnumerateEntries("/", "*.tik"))
{ {
Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); Result result = nsp.OpenFile(out IFile ticketFile, ticketEntry.FullPath, OpenMode.Read);
if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId)) if (result.IsSuccess())
{ {
KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet)); Ticket ticket = new Ticket(ticketFile.AsStream());
KeySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(KeySet)));
} }
} }
@ -371,15 +403,15 @@ namespace Ryujinx.HLE.HOS
Nca patchNca = null; Nca patchNca = null;
Nca controlNca = null; Nca controlNca = null;
foreach (DirectoryEntry fileEntry in nsp.EnumerateEntries("*.nca")) foreach (DirectoryEntryEx fileEntry in nsp.EnumerateEntries("/", "*.nca"))
{ {
IStorage ncaStorage = nsp.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage(); nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
Nca nca = new Nca(KeySet, ncaStorage); Nca nca = new Nca(KeySet, ncaFile.AsStorage());
if (nca.Header.ContentType == ContentType.Program) if (nca.Header.ContentType == NcaContentType.Program)
{ {
int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, ContentType.Program); int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
if (nca.Header.GetFsHeader(dataIndex).IsPatchSection()) if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
{ {
@ -390,7 +422,7 @@ namespace Ryujinx.HLE.HOS
mainNca = nca; mainNca = nca;
} }
} }
else if (nca.Header.ContentType == ContentType.Control) else if (nca.Header.ContentType == NcaContentType.Control)
{ {
controlNca = nca; controlNca = nca;
} }
@ -409,7 +441,7 @@ namespace Ryujinx.HLE.HOS
public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca) public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca)
{ {
if (mainNca.Header.ContentType != ContentType.Program) if (mainNca.Header.ContentType != NcaContentType.Program)
{ {
Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA"); Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");
@ -466,7 +498,7 @@ namespace Ryujinx.HLE.HOS
{ {
IFileSystem controlRomfs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel); IFileSystem controlRomfs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
IFile controlFile = controlRomfs.OpenFile("/control.nacp", OpenMode.Read); controlRomfs.OpenFile(out IFile controlFile, "/control.nacp", OpenMode.Read).ThrowIfFailure();
Nacp controlData = new Nacp(controlFile.AsStream()); Nacp controlData = new Nacp(controlFile.AsStream());
@ -493,24 +525,24 @@ namespace Ryujinx.HLE.HOS
private void LoadExeFs(IFileSystem codeFs, out Npdm metaData) private void LoadExeFs(IFileSystem codeFs, out Npdm metaData)
{ {
if (codeFs.FileExists("/main.npdm")) Result result = codeFs.OpenFile(out IFile npdmFile, "/main.npdm", OpenMode.Read);
{
Logger.PrintInfo(LogClass.Loader, "Loading main.npdm...");
metaData = new Npdm(codeFs.OpenFile("/main.npdm", OpenMode.Read).AsStream()); if (result == ResultFs.PathNotFound)
}
else
{ {
Logger.PrintWarning(LogClass.Loader, "NPDM file not found, using default values!"); Logger.PrintWarning(LogClass.Loader, "NPDM file not found, using default values!");
metaData = GetDefaultNpdm(); metaData = GetDefaultNpdm();
} }
else
{
metaData = new Npdm(npdmFile.AsStream());
}
List<IExecutable> staticObjects = new List<IExecutable>(); List<IExecutable> staticObjects = new List<IExecutable>();
void LoadNso(string filename) void LoadNso(string filename)
{ {
foreach (DirectoryEntry file in codeFs.EnumerateEntries($"{filename}*")) foreach (DirectoryEntryEx file in codeFs.EnumerateEntries("/", $"{filename}*"))
{ {
if (Path.GetExtension(file.Name) != string.Empty) if (Path.GetExtension(file.Name) != string.Empty)
{ {
@ -519,7 +551,9 @@ namespace Ryujinx.HLE.HOS
Logger.PrintInfo(LogClass.Loader, $"Loading {file.Name}..."); Logger.PrintInfo(LogClass.Loader, $"Loading {file.Name}...");
NxStaticObject staticObject = new NxStaticObject(codeFs.OpenFile(file.FullPath, OpenMode.Read).AsStream()); codeFs.OpenFile(out IFile nsoFile, file.FullPath, OpenMode.Read).ThrowIfFailure();
NxStaticObject staticObject = new NxStaticObject(nsoFile.AsStream());
staticObjects.Add(staticObject); staticObjects.Add(staticObject);
} }
@ -654,7 +688,7 @@ namespace Ryujinx.HLE.HOS
LoadSetAtPath(Path.Combine(home, ".switch")); LoadSetAtPath(Path.Combine(home, ".switch"));
LoadSetAtPath(Device.FileSystem.GetSystemPath()); LoadSetAtPath(Device.FileSystem.GetSystemPath());
KeySet = ExternalKeys.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile); KeySet = ExternalKeyReader.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile);
void LoadSetAtPath(string basePath) void LoadSetAtPath(string basePath)
{ {

View file

@ -1,6 +1,8 @@
using LibHac; using LibHac;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.NcaUtils; using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using LibHac.Spl;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
@ -25,7 +27,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
try try
{ {
LocalFileSystem fileSystem = new LocalFileSystem(savePath); LocalFileSystem fileSystem = new LocalFileSystem(savePath);
LibHac.Fs.IFileSystem saveFileSystem = new DirectorySaveDataFileSystem(fileSystem);
Result result = DirectorySaveDataFileSystem.CreateNew(out DirectorySaveDataFileSystem dirFileSystem, fileSystem);
if (result.IsFailure())
{
return (ResultCode)result.Value;
}
LibHac.Fs.IFileSystem saveFileSystem = dirFileSystem;
if (readOnly) if (readOnly)
{ {
@ -111,13 +120,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage()); PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage());
ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet);
string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\');
if (nsp.FileExists(filename)) Result result = nsp.OpenFile(out LibHac.Fs.IFile ncaFile, filename, OpenMode.Read);
if (result.IsFailure())
{ {
return OpenNcaFs(context, fullPath, nsp.OpenFile(filename, OpenMode.Read).AsStorage(), out openedFileSystem); return (ResultCode)result.Value;
} }
return OpenNcaFs(context, fullPath, ncaFile.AsStorage(), out openedFileSystem);
} }
catch (HorizonResultException ex) catch (HorizonResultException ex)
{ {
@ -130,15 +142,17 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
public static void ImportTitleKeysFromNsp(LibHac.Fs.IFileSystem nsp, Keyset keySet) public static void ImportTitleKeysFromNsp(LibHac.Fs.IFileSystem nsp, Keyset keySet)
{ {
foreach (DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik")) foreach (DirectoryEntryEx ticketEntry in nsp.EnumerateEntries("/", "*.tik"))
{ {
Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); Result result = nsp.OpenFile(out LibHac.Fs.IFile ticketFile, ticketEntry.FullPath, OpenMode.Read);
if (!keySet.TitleKeys.ContainsKey(ticket.RightsId)) if (result.IsSuccess())
{ {
keySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(keySet)); Ticket ticket = new Ticket(ticketFile.AsStream());
keySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(keySet)));
} }
} }
} }
} }
} }

View file

@ -1,21 +1,17 @@
using LibHac; using LibHac;
using System.Collections.Generic; using LibHac.Fs;
using System.Text; using System;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
class IDirectory : IpcService class IDirectory : IpcService
{ {
private const int DirectoryEntrySize = 0x310;
private IEnumerator<LibHac.Fs.DirectoryEntry> _enumerator;
private LibHac.Fs.IDirectory _baseDirectory; private LibHac.Fs.IDirectory _baseDirectory;
public IDirectory(LibHac.Fs.IDirectory directory) public IDirectory(LibHac.Fs.IDirectory directory)
{ {
_baseDirectory = directory; _baseDirectory = directory;
_enumerator = directory.Read().GetEnumerator();
} }
[Command(0)] [Command(0)]
@ -25,60 +21,26 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
long bufferPosition = context.Request.ReceiveBuff[0].Position; long bufferPosition = context.Request.ReceiveBuff[0].Position;
long bufferLen = context.Request.ReceiveBuff[0].Size; long bufferLen = context.Request.ReceiveBuff[0].Size;
int maxReadCount = (int)(bufferLen / DirectoryEntrySize); byte[] entriesBytes = new byte[bufferLen];
int readCount = 0; Span<DirectoryEntry> entries = MemoryMarshal.Cast<byte, DirectoryEntry>(entriesBytes);
try Result result = _baseDirectory.Read(out long entriesRead, entries);
{
while (readCount < maxReadCount && _enumerator.MoveNext())
{
long position = bufferPosition + readCount * DirectoryEntrySize;
WriteDirectoryEntry(context, position, _enumerator.Current); context.Memory.WriteBytes(bufferPosition, entriesBytes);
context.ResponseData.Write(entriesRead);
readCount++; return (ResultCode)result.Value;
}
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
context.ResponseData.Write((long)readCount);
return ResultCode.Success;
}
private void WriteDirectoryEntry(ServiceCtx context, long position, LibHac.Fs.DirectoryEntry entry)
{
for (int offset = 0; offset < 0x300; offset += 8)
{
context.Memory.WriteInt64(position + offset, 0);
}
byte[] nameBuffer = Encoding.UTF8.GetBytes(entry.Name);
context.Memory.WriteBytes(position, nameBuffer);
context.Memory.WriteInt32(position + 0x300, (int)entry.Attributes);
context.Memory.WriteInt32(position + 0x304, (byte)entry.Type);
context.Memory.WriteInt64(position + 0x308, entry.Size);
} }
[Command(1)] [Command(1)]
// GetEntryCount() -> u64 // GetEntryCount() -> u64
public ResultCode GetEntryCount(ServiceCtx context) public ResultCode GetEntryCount(ServiceCtx context)
{ {
try Result result = _baseDirectory.GetEntryCount(out long entryCount);
{
context.ResponseData.Write((long)_baseDirectory.GetEntryCount());
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; context.ResponseData.Write(entryCount);
return (ResultCode)result.Value;
} }
} }
} }

View file

@ -26,22 +26,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
long size = context.RequestData.ReadInt64(); long size = context.RequestData.ReadInt64();
byte[] data = new byte[size]; byte[] data = new byte[size];
int readSize;
try Result result = _baseFile.Read(out long bytesRead, offset, data, readOption);
{
readSize = _baseFile.Read(data, offset, readOption);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
context.Memory.WriteBytes(position, data); context.Memory.WriteBytes(position, data);
context.ResponseData.Write((long)readSize); context.ResponseData.Write(bytesRead);
return ResultCode.Success; return (ResultCode)result.Value;
} }
[Command(1)] [Command(1)]
@ -58,66 +50,34 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
byte[] data = context.Memory.ReadBytes(position, size); byte[] data = context.Memory.ReadBytes(position, size);
try return (ResultCode)_baseFile.Write(offset, data, writeOption).Value;
{
_baseFile.Write(data, offset, writeOption);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(2)] [Command(2)]
// Flush() // Flush()
public ResultCode Flush(ServiceCtx context) public ResultCode Flush(ServiceCtx context)
{ {
try return (ResultCode)_baseFile.Flush().Value;
{
_baseFile.Flush();
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(3)] [Command(3)]
// SetSize(u64 size) // SetSize(u64 size)
public ResultCode SetSize(ServiceCtx context) public ResultCode SetSize(ServiceCtx context)
{ {
try long size = context.RequestData.ReadInt64();
{
long size = context.RequestData.ReadInt64();
_baseFile.SetSize(size); return (ResultCode)_baseFile.SetSize(size).Value;
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(4)] [Command(4)]
// GetSize() -> u64 fileSize // GetSize() -> u64 fileSize
public ResultCode GetSize(ServiceCtx context) public ResultCode GetSize(ServiceCtx context)
{ {
try Result result = _baseFile.GetSize(out long size);
{
context.ResponseData.Write(_baseFile.GetSize());
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; context.ResponseData.Write(size);
return (ResultCode)result.Value;
} }
public void Dispose() public void Dispose()

View file

@ -25,16 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
long size = context.RequestData.ReadInt64(); long size = context.RequestData.ReadInt64();
try return (ResultCode)_fileSystem.CreateFile(name, size, createOption).Value;
{
_fileSystem.CreateFile(name, size, createOption);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(1)] [Command(1)]
@ -43,16 +34,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try return (ResultCode)_fileSystem.DeleteFile(name).Value;
{
_fileSystem.DeleteFile(name);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(2)] [Command(2)]
@ -61,16 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try return (ResultCode)_fileSystem.CreateDirectory(name).Value;
{
_fileSystem.CreateDirectory(name);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(3)] [Command(3)]
@ -79,16 +52,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try return (ResultCode)_fileSystem.DeleteDirectory(name).Value;
{
_fileSystem.DeleteDirectory(name);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(4)] [Command(4)]
@ -97,16 +61,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try return (ResultCode)_fileSystem.DeleteDirectoryRecursively(name).Value;
{
_fileSystem.DeleteDirectoryRecursively(name);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(5)] [Command(5)]
@ -116,16 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
string oldName = ReadUtf8String(context, 0); string oldName = ReadUtf8String(context, 0);
string newName = ReadUtf8String(context, 1); string newName = ReadUtf8String(context, 1);
try return (ResultCode)_fileSystem.RenameFile(oldName, newName).Value;
{
_fileSystem.RenameFile(oldName, newName);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(6)] [Command(6)]
@ -135,16 +81,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
string oldName = ReadUtf8String(context, 0); string oldName = ReadUtf8String(context, 0);
string newName = ReadUtf8String(context, 1); string newName = ReadUtf8String(context, 1);
try return (ResultCode)_fileSystem.RenameDirectory(oldName, newName).Value;
{
_fileSystem.RenameDirectory(oldName, newName);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(7)] [Command(7)]
@ -153,25 +90,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try Result result = _fileSystem.GetEntryType(out DirectoryEntryType entryType, name);
{
DirectoryEntryType entryType = _fileSystem.GetEntryType(name);
if (entryType == DirectoryEntryType.Directory || entryType == DirectoryEntryType.File) context.ResponseData.Write((int)entryType);
{
context.ResponseData.Write((int)entryType);
}
else
{
return ResultCode.PathDoesNotExist;
}
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; return (ResultCode)result.Value;
} }
[Command(8)] [Command(8)]
@ -182,20 +105,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try Result result = _fileSystem.OpenFile(out LibHac.Fs.IFile file, name, mode);
{
LibHac.Fs.IFile file = _fileSystem.OpenFile(name, mode);
if (result.IsSuccess())
{
IFile fileInterface = new IFile(file); IFile fileInterface = new IFile(file);
MakeObject(context, fileInterface); MakeObject(context, fileInterface);
} }
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; return (ResultCode)result.Value;
} }
[Command(9)] [Command(9)]
@ -206,36 +125,23 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try Result result = _fileSystem.OpenDirectory(out LibHac.Fs.IDirectory dir, name, mode);
{
LibHac.Fs.IDirectory dir = _fileSystem.OpenDirectory(name, mode);
if (result.IsSuccess())
{
IDirectory dirInterface = new IDirectory(dir); IDirectory dirInterface = new IDirectory(dir);
MakeObject(context, dirInterface); MakeObject(context, dirInterface);
} }
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; return (ResultCode)result.Value;
} }
[Command(10)] [Command(10)]
// Commit() // Commit()
public ResultCode Commit(ServiceCtx context) public ResultCode Commit(ServiceCtx context)
{ {
try return (ResultCode)_fileSystem.Commit().Value;
{
_fileSystem.Commit();
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(11)] [Command(11)]
@ -244,16 +150,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try Result result = _fileSystem.GetFreeSpaceSize(out long size, name);
{
context.ResponseData.Write(_fileSystem.GetFreeSpaceSize(name));
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; context.ResponseData.Write(size);
return (ResultCode)result.Value;
} }
[Command(12)] [Command(12)]
@ -262,16 +163,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try Result result = _fileSystem.GetTotalSpaceSize(out long size, name);
{
context.ResponseData.Write(_fileSystem.GetTotalSpaceSize(name));
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; context.ResponseData.Write(size);
return (ResultCode)result.Value;
} }
[Command(13)] [Command(13)]
@ -280,16 +176,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try return (ResultCode)_fileSystem.CleanDirectoryRecursively(name).Value;
{
_fileSystem.CleanDirectoryRecursively(name);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success;
} }
[Command(14)] [Command(14)]
@ -298,27 +185,20 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{ {
string name = ReadUtf8String(context); string name = ReadUtf8String(context);
try Result result = _fileSystem.GetFileTimeStampRaw(out FileTimeStampRaw timestamp, name);
{
FileTimeStampRaw timestamp = _fileSystem.GetFileTimeStampRaw(name);
context.ResponseData.Write(timestamp.Created); context.ResponseData.Write(timestamp.Created);
context.ResponseData.Write(timestamp.Modified); context.ResponseData.Write(timestamp.Modified);
context.ResponseData.Write(timestamp.Accessed); context.ResponseData.Write(timestamp.Accessed);
byte[] data = new byte[8]; byte[] data = new byte[8];
// is valid? // is valid?
data[0] = 1; data[0] = 1;
context.ResponseData.Write(data); context.ResponseData.Write(data);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; return (ResultCode)result.Value;
} }
} }
} }

View file

@ -31,16 +31,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
byte[] data = new byte[size]; byte[] data = new byte[size];
try Result result = _baseStorage.Read(offset, data);
{
_baseStorage.Read(data, offset);
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
context.Memory.WriteBytes(buffDesc.Position, data); context.Memory.WriteBytes(buffDesc.Position, data);
return (ResultCode)result.Value;
} }
return ResultCode.Success; return ResultCode.Success;
@ -50,16 +45,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
// GetSize() -> u64 size // GetSize() -> u64 size
public ResultCode GetSize(ServiceCtx context) public ResultCode GetSize(ServiceCtx context)
{ {
try Result result = _baseStorage.GetSize(out long size);
{
context.ResponseData.Write(_baseStorage.GetSize());
}
catch (HorizonResultException ex)
{
return (ResultCode)ex.ResultValue.Value;
}
return ResultCode.Success; context.ResponseData.Write(size);
return (ResultCode)result.Value;
} }
} }
} }

View file

@ -0,0 +1,37 @@
using LibHac;
using LibHac.FsService;
namespace Ryujinx.HLE.HOS.Services.Fs
{
class IDeviceOperator : IpcService
{
private LibHac.FsService.IDeviceOperator _baseOperator;
public IDeviceOperator(LibHac.FsService.IDeviceOperator baseOperator)
{
_baseOperator = baseOperator;
}
[Command(200)]
// IsGameCardInserted() -> b8 is_inserted
public ResultCode IsGameCardInserted(ServiceCtx context)
{
Result result = _baseOperator.IsGameCardInserted(out bool isInserted);
context.ResponseData.Write(isInserted);
return (ResultCode)result.Value;
}
[Command(202)]
// GetGameCardHandle() -> u32 gamecard_handle
public ResultCode GetGameCardHandle(ServiceCtx context)
{
Result result = _baseOperator.GetGameCardHandle(out GameCardHandle handle);
context.ResponseData.Write(handle.Value);
return (ResultCode)result.Value;
}
}
}

View file

@ -1,6 +1,8 @@
using LibHac; using LibHac;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.NcaUtils; using LibHac.FsService;
using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy; using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy;
@ -14,7 +16,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs
[Service("fsp-srv")] [Service("fsp-srv")]
class IFileSystemProxy : IpcService class IFileSystemProxy : IpcService
{ {
public IFileSystemProxy(ServiceCtx context) { } private LibHac.FsService.IFileSystemProxy _baseFileSystemProxy;
public IFileSystemProxy(ServiceCtx context)
{
_baseFileSystemProxy = context.Device.System.FsServer.CreateFileSystemProxyService();
}
[Command(1)] [Command(1)]
// Initialize(u64, pid) // Initialize(u64, pid)
@ -125,6 +132,23 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return ResultCode.Success; return ResultCode.Success;
} }
[Command(30)]
// OpenGameCardStorage(u32, u32) -> object<nn::fssrv::sf::IStorage>
public ResultCode OpenGameCardStorage(ServiceCtx context)
{
GameCardHandle handle = new GameCardHandle(context.RequestData.ReadInt32());
GameCardPartitionRaw partitionId = (GameCardPartitionRaw)context.RequestData.ReadInt32();
Result result = _baseFileSystemProxy.OpenGameCardStorage(out LibHac.Fs.IStorage storage, handle, partitionId);
if (result.IsSuccess())
{
MakeObject(context, new FileSystemProxy.IStorage(storage));
}
return (ResultCode)result.Value;
}
[Command(51)] [Command(51)]
// OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> saveDataFs // OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> saveDataFs
public ResultCode OpenSaveDataFileSystem(ServiceCtx context) public ResultCode OpenSaveDataFileSystem(ServiceCtx context)
@ -184,14 +208,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs
byte[] padding = context.RequestData.ReadBytes(7); byte[] padding = context.RequestData.ReadBytes(7);
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
ContentType contentType = ContentType.Data; NcaContentType contentType = NcaContentType.Data;
StorageId installedStorage = StorageId installedStorage =
context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId); context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId);
if (installedStorage == StorageId.None) if (installedStorage == StorageId.None)
{ {
contentType = ContentType.PublicData; contentType = NcaContentType.PublicData;
installedStorage = installedStorage =
context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId); context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId);
@ -246,6 +270,20 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return ResultCode.Success; return ResultCode.Success;
} }
[Command(400)]
// OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
public ResultCode OpenDeviceOperator(ServiceCtx context)
{
Result result = _baseFileSystemProxy.OpenDeviceOperator(out LibHac.FsService.IDeviceOperator deviceOperator);
if (result.IsSuccess())
{
MakeObject(context, new IDeviceOperator(deviceOperator));
}
return (ResultCode)result.Value;
}
[Command(1005)] [Command(1005)]
// GetGlobalAccessLogMode() -> u32 logMode // GetGlobalAccessLogMode() -> u32 logMode
public ResultCode GetGlobalAccessLogMode(ServiceCtx context) public ResultCode GetGlobalAccessLogMode(ServiceCtx context)

View file

@ -1,4 +1,4 @@
using LibHac.Fs.NcaUtils; using LibHac.FsSystem.NcaUtils;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem.Content;
using System.Text; using System.Text;
@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
if (ResolvePath(context, titleId, ContentType.Program)) if (ResolvePath(context, titleId, NcaContentType.Program))
{ {
return ResultCode.Success; return ResultCode.Success;
} }
@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
RedirectPath(context, titleId, 0, ContentType.Program); RedirectPath(context, titleId, 0, NcaContentType.Program);
return ResultCode.Success; return ResultCode.Success;
} }
@ -49,7 +49,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
if (ResolvePath(context, titleId, ContentType.Control)) if (ResolvePath(context, titleId, NcaContentType.Control))
{ {
return ResultCode.Success; return ResultCode.Success;
} }
@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
if (ResolvePath(context, titleId, ContentType.Manual)) if (ResolvePath(context, titleId, NcaContentType.Manual))
{ {
return ResultCode.Success; return ResultCode.Success;
} }
@ -81,7 +81,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
if (ResolvePath(context, titleId, ContentType.Data) || ResolvePath(context, titleId, ContentType.PublicData)) if (ResolvePath(context, titleId, NcaContentType.Data) || ResolvePath(context, titleId, NcaContentType.PublicData))
{ {
return ResultCode.Success; return ResultCode.Success;
} }
@ -97,7 +97,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
RedirectPath(context, titleId, 1, ContentType.Control); RedirectPath(context, titleId, 1, NcaContentType.Control);
return ResultCode.Success; return ResultCode.Success;
} }
@ -108,7 +108,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
RedirectPath(context, titleId, 1, ContentType.Manual); RedirectPath(context, titleId, 1, NcaContentType.Manual);
return ResultCode.Success; return ResultCode.Success;
} }
@ -119,7 +119,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
if (ResolvePath(context, titleId, ContentType.Manual)) if (ResolvePath(context, titleId, NcaContentType.Manual))
{ {
return ResultCode.Success; return ResultCode.Success;
} }
@ -135,7 +135,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
RedirectPath(context, titleId, 1, ContentType.Manual); RedirectPath(context, titleId, 1, NcaContentType.Manual);
return ResultCode.Success; return ResultCode.Success;
} }
@ -155,7 +155,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
RedirectPath(context, titleId, 1, ContentType.Program); RedirectPath(context, titleId, 1, NcaContentType.Program);
return ResultCode.Success; return ResultCode.Success;
} }
@ -175,7 +175,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
DeleteContentPath(context, titleId, ContentType.Program); DeleteContentPath(context, titleId, NcaContentType.Program);
return ResultCode.Success; return ResultCode.Success;
} }
@ -186,7 +186,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
DeleteContentPath(context, titleId, ContentType.Control); DeleteContentPath(context, titleId, NcaContentType.Control);
return ResultCode.Success; return ResultCode.Success;
} }
@ -197,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
DeleteContentPath(context, titleId, ContentType.Manual); DeleteContentPath(context, titleId, NcaContentType.Manual);
return ResultCode.Success; return ResultCode.Success;
} }
@ -208,12 +208,12 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
{ {
long titleId = context.RequestData.ReadInt64(); long titleId = context.RequestData.ReadInt64();
DeleteContentPath(context, titleId, ContentType.Manual); DeleteContentPath(context, titleId, NcaContentType.Manual);
return ResultCode.Success; return ResultCode.Success;
} }
private void RedirectPath(ServiceCtx context, long titleId, int flag, ContentType contentType) private void RedirectPath(ServiceCtx context, long titleId, int flag, NcaContentType contentType)
{ {
string contentPath = ReadUtf8String(context); string contentPath = ReadUtf8String(context);
LocationEntry newLocation = new LocationEntry(contentPath, flag, titleId, contentType); LocationEntry newLocation = new LocationEntry(contentPath, flag, titleId, contentType);
@ -221,10 +221,10 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
context.Device.System.ContentManager.RedirectLocation(newLocation, _storageId); context.Device.System.ContentManager.RedirectLocation(newLocation, _storageId);
} }
private bool ResolvePath(ServiceCtx context, long titleId,ContentType contentType) private bool ResolvePath(ServiceCtx context, long titleId, NcaContentType contentType)
{ {
ContentManager contentManager = context.Device.System.ContentManager; ContentManager contentManager = context.Device.System.ContentManager;
string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, ContentType.Program); string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, NcaContentType.Program);
if (!string.IsNullOrWhiteSpace(contentPath)) if (!string.IsNullOrWhiteSpace(contentPath))
{ {
@ -243,12 +243,12 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
return true; return true;
} }
private void DeleteContentPath(ServiceCtx context, long titleId, ContentType contentType) private void DeleteContentPath(ServiceCtx context, long titleId, NcaContentType contentType)
{ {
ContentManager contentManager = context.Device.System.ContentManager; ContentManager contentManager = context.Device.System.ContentManager;
string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, ContentType.Manual); string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, NcaContentType.Manual);
contentManager.ClearEntry(titleId, ContentType.Manual, _storageId); contentManager.ClearEntry(titleId, NcaContentType.Manual, _storageId);
} }
} }
} }

View file

@ -1,5 +1,7 @@
using LibHac;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.NcaUtils; using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
@ -165,7 +167,7 @@ namespace Ryujinx.HLE.HOS.Services.Settings
public byte[] GetFirmwareData(Switch device) public byte[] GetFirmwareData(Switch device)
{ {
long titleId = 0x0100000000000809; long titleId = 0x0100000000000809;
string contentPath = device.System.ContentManager.GetInstalledContentPath(titleId, StorageId.NandSystem, ContentType.Data); string contentPath = device.System.ContentManager.GetInstalledContentPath(titleId, StorageId.NandSystem, NcaContentType.Data);
if (string.IsNullOrWhiteSpace(contentPath)) if (string.IsNullOrWhiteSpace(contentPath))
{ {
@ -185,11 +187,25 @@ namespace Ryujinx.HLE.HOS.Services.Settings
IFileSystem firmwareRomFs = firmwareContent.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel); IFileSystem firmwareRomFs = firmwareContent.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel);
IFile firmwareFile = firmwareRomFs.OpenFile("/file", OpenMode.Read); Result result = firmwareRomFs.OpenFile(out IFile firmwareFile, "/file", OpenMode.Read);
if (result.IsFailure())
{
return null;
}
byte[] data = new byte[firmwareFile.GetSize()]; result = firmwareFile.GetSize(out long fileSize);
if (result.IsFailure())
{
return null;
}
firmwareFile.Read(data, 0); byte[] data = new byte[fileSize];
result = firmwareFile.Read(out _, 0, data);
if (result.IsFailure())
{
return null;
}
return data; return data;
} }

View file

@ -1,5 +1,7 @@
using LibHac.Fs; using LibHac;
using LibHac.Fs.NcaUtils; using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
@ -58,9 +60,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
Nca nca = new Nca(_device.System.KeySet, ncaFileStream); Nca nca = new Nca(_device.System.KeySet, ncaFileStream);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
Stream binaryListStream = romfs.OpenFile("binaryList.txt", OpenMode.Read).AsStream();
StreamReader reader = new StreamReader(binaryListStream); romfs.OpenFile(out IFile binaryListFile, "/binaryList.txt", OpenMode.Read).ThrowIfFailure();
StreamReader reader = new StreamReader(binaryListFile.AsStream());
List<string> locationNameList = new List<string>(); List<string> locationNameList = new List<string>();
@ -139,7 +142,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
public string GetTimeZoneBinaryTitleContentPath() public string GetTimeZoneBinaryTitleContentPath()
{ {
return _device.System.ContentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.NandSystem, ContentType.Data); return _device.System.ContentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.NandSystem, NcaContentType.Data);
} }
public bool HasTimeZoneBinaryTitle() public bool HasTimeZoneBinaryTitle()
@ -162,9 +165,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
Nca nca = new Nca(_device.System.KeySet, ncaFile); Nca nca = new Nca(_device.System.KeySet, ncaFile);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel); IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
timeZoneBinaryStream = romfs.OpenFile($"/zoneinfo/{locationName}", OpenMode.Read).AsStream(); Result result = romfs.OpenFile(out IFile timeZoneBinaryFile, $"/zoneinfo/{locationName}", OpenMode.Read);
return ResultCode.Success; timeZoneBinaryStream = timeZoneBinaryFile.AsStream();
return (ResultCode)result.Value;
} }
internal ResultCode LoadTimeZoneRule(out TimeZoneRule outRules, string locationName) internal ResultCode LoadTimeZoneRule(out TimeZoneRule outRules, string locationName)

View file

@ -48,7 +48,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Concentus" Version="1.1.7" /> <PackageReference Include="Concentus" Version="1.1.7" />
<PackageReference Include="LibHac" Version="0.5.1" /> <PackageReference Include="LibHac" Version="0.6.0" />
<PackageReference Include="System.Runtime.Intrinsics.Experimental" Version="4.5.0-rc1" /> <PackageReference Include="System.Runtime.Intrinsics.Experimental" Version="4.5.0-rc1" />
<PackageReference Include="TimeZoneConverter.Posix" Version="2.1.0" /> <PackageReference Include="TimeZoneConverter.Posix" Version="2.1.0" />
</ItemGroup> </ItemGroup>

View file

@ -1,5 +1,5 @@
using JsonPrettyPrinterPlus; using JsonPrettyPrinterPlus;
using LibHac.Fs; using LibHac.FsSystem;
using OpenTK.Input; using OpenTK.Input;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;

View file

@ -1,6 +1,8 @@
using LibHac; using LibHac;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.NcaUtils; using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using LibHac.Spl;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -8,6 +10,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using SystemState = Ryujinx.HLE.HOS.SystemState; using SystemState = Ryujinx.HLE.HOS.SystemState;
namespace Ryujinx.UI namespace Ryujinx.UI
@ -115,8 +118,9 @@ namespace Ryujinx.UI
} }
// Creates NACP class from the NACP file // Creates NACP class from the NACP file
IFile controlNacp = controlFs.OpenFile("/control.nacp", OpenMode.Read); controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp", OpenMode.Read).ThrowIfFailure();
Nacp controlData = new Nacp(controlNacp.AsStream());
Nacp controlData = new Nacp(controlNacpFile.AsStream());
// Get the title name, title ID, developer name and version number from the NACP // Get the title name, title ID, developer name and version number from the NACP
version = controlData.DisplayVersion; version = controlData.DisplayVersion;
@ -150,7 +154,8 @@ namespace Ryujinx.UI
// Read the icon from the ControlFS and store it as a byte array // Read the icon from the ControlFS and store it as a byte array
try try
{ {
IFile icon = controlFs.OpenFile($"/icon_{DesiredTitleLanguage}.dat", OpenMode.Read); controlFs.OpenFile(out IFile icon, $"/icon_{DesiredTitleLanguage}.dat", OpenMode.Read).ThrowIfFailure();
using (MemoryStream stream = new MemoryStream()) using (MemoryStream stream = new MemoryStream())
{ {
icon.AsStream().CopyTo(stream); icon.AsStream().CopyTo(stream);
@ -159,15 +164,15 @@ namespace Ryujinx.UI
} }
catch (HorizonResultException) catch (HorizonResultException)
{ {
IDirectory controlDir = controlFs.OpenDirectory("./", OpenDirectoryMode.All); foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
foreach (DirectoryEntry entry in controlDir.Read())
{ {
if (entry.Name == "control.nacp") if (entry.Name == "control.nacp")
{ {
continue; continue;
} }
IFile icon = controlFs.OpenFile(entry.FullPath, OpenMode.Read); controlFs.OpenFile(out IFile icon, entry.FullPath, OpenMode.Read).ThrowIfFailure();
using (MemoryStream stream = new MemoryStream()) using (MemoryStream stream = new MemoryStream())
{ {
icon.AsStream().CopyTo(stream); icon.AsStream().CopyTo(stream);
@ -346,21 +351,26 @@ namespace Ryujinx.UI
Nca controlNca = null; Nca controlNca = null;
// Add keys to keyset if needed // Add keys to keyset if needed
foreach (DirectoryEntry ticketEntry in Pfs.EnumerateEntries("*.tik")) foreach (DirectoryEntryEx ticketEntry in Pfs.EnumerateEntries("/", "*.tik"))
{ {
Ticket ticket = new Ticket(Pfs.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); Result result = Pfs.OpenFile(out IFile ticketFile, ticketEntry.FullPath, OpenMode.Read);
if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId)) if (result.IsSuccess())
{ {
KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet)); Ticket ticket = new Ticket(ticketFile.AsStream());
KeySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(KeySet)));
} }
} }
// Find the Control NCA and store it in variable called controlNca // Find the Control NCA and store it in variable called controlNca
foreach (DirectoryEntry fileEntry in Pfs.EnumerateEntries("*.nca")) foreach (DirectoryEntryEx fileEntry in Pfs.EnumerateEntries("/", "*.nca"))
{ {
Nca nca = new Nca(KeySet, Pfs.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage()); Pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
if (nca.Header.ContentType == ContentType.Control)
Nca nca = new Nca(KeySet, ncaFile.AsStorage());
if (nca.Header.ContentType == NcaContentType.Control)
{ {
controlNca = nca; controlNca = nca;
} }