Browse Source

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
Alex Barney 6 years ago
parent
commit
8a8ea4c8c0

+ 16 - 16
Ryujinx.HLE/FileSystem/Content/ContentManager.cs

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

+ 6 - 6
Ryujinx.HLE/FileSystem/Content/LocationEntry.cs

@@ -1,15 +1,15 @@
-using LibHac.Fs.NcaUtils;
+using LibHac.FsSystem.NcaUtils;
 
 namespace Ryujinx.HLE.FileSystem.Content
 {
     public struct LocationEntry
     {
-        public string      ContentPath { get; private set; }
-        public int         Flag        { get; private set; }
-        public long        TitleId     { get; private set; }
-        public ContentType ContentType { get; private set; }
+        public string         ContentPath { get; private set; }
+        public int            Flag        { get; private set; }
+        public long           TitleId     { 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;
             Flag        = flag;

+ 3 - 2
Ryujinx.HLE/FileSystem/SaveHelper.cs

@@ -1,4 +1,5 @@
 using LibHac.Fs;
+using LibHac.FsSystem;
 using Ryujinx.HLE.HOS;
 using System.IO;
 
@@ -21,9 +22,9 @@ namespace Ryujinx.HLE.FileSystem
 
                 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);

+ 6 - 4
Ryujinx.HLE/HOS/Font/SharedFontManager.cs

@@ -1,5 +1,6 @@
 using LibHac.Fs;
-using LibHac.Fs.NcaUtils;
+using LibHac.FsSystem;
+using LibHac.FsSystem.NcaUtils;
 using Ryujinx.Common;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.FileSystem;
@@ -55,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Font
                     if (contentManager.TryGetFontTitle(name, out long fontTitle) &&
                         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);
 
                         if (!string.IsNullOrWhiteSpace(fontPath))
@@ -66,9 +67,10 @@ namespace Ryujinx.HLE.HOS.Font
                             {
                                 Nca         nca          = new Nca(_device.System.KeySet, ncaFileStream);
                                 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);

+ 69 - 35
Ryujinx.HLE/HOS/Horizon.cs

@@ -1,6 +1,9 @@
 using LibHac;
 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.HLE.FileSystem.Content;
 using Ryujinx.HLE.HOS.Font;
@@ -116,6 +119,9 @@ namespace Ryujinx.HLE.HOS
 
         internal long HidBaseAddress { get; private set; }
 
+        internal FileSystemServer FsServer { get; private set; }
+        internal EmulatedGameCard GameCard { get; private set; }
+
         public Horizon(Switch device)
         {
             ControlData = new Nacp();
@@ -228,6 +234,21 @@ namespace Ryujinx.HLE.HOS
             // FIXME: TimeZone shoud be init here but it's actually done in ContentManager
 
             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)
@@ -283,25 +304,31 @@ namespace Ryujinx.HLE.HOS
 
             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())
+                {
+                    continue;
+                }
 
-                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())
                     {
@@ -312,7 +339,7 @@ namespace Ryujinx.HLE.HOS
                         mainNca = nca;
                     }
                 }
-                else if (nca.Header.ContentType == ContentType.Control)
+                else if (nca.Header.ContentType == NcaContentType.Control)
                 {
                     controlNca = nca;
                 }
@@ -335,11 +362,14 @@ namespace Ryujinx.HLE.HOS
         {
             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)
@@ -357,13 +387,15 @@ namespace Ryujinx.HLE.HOS
 
             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 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())
                     {
@@ -390,7 +422,7 @@ namespace Ryujinx.HLE.HOS
                         mainNca = nca;
                     }
                 }
-                else if (nca.Header.ContentType == ContentType.Control)
+                else if (nca.Header.ContentType == NcaContentType.Control)
                 {
                     controlNca = nca;
                 }
@@ -409,7 +441,7 @@ namespace Ryujinx.HLE.HOS
 
         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");
 
@@ -466,7 +498,7 @@ namespace Ryujinx.HLE.HOS
             {
                 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());
 
@@ -493,24 +525,24 @@ namespace Ryujinx.HLE.HOS
 
         private void LoadExeFs(IFileSystem codeFs, out Npdm metaData)
         {
-            if (codeFs.FileExists("/main.npdm"))
-            {
-                Logger.PrintInfo(LogClass.Loader, "Loading main.npdm...");
+            Result result = codeFs.OpenFile(out IFile npdmFile, "/main.npdm", OpenMode.Read);
 
-                metaData = new Npdm(codeFs.OpenFile("/main.npdm", OpenMode.Read).AsStream());
-            }
-            else
+            if (result == ResultFs.PathNotFound)
             {
                 Logger.PrintWarning(LogClass.Loader, "NPDM file not found, using default values!");
 
                 metaData = GetDefaultNpdm();
             }
+            else
+            {
+                metaData = new Npdm(npdmFile.AsStream());
+            }
 
             List<IExecutable> staticObjects = new List<IExecutable>();
 
             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)
                     {
@@ -519,7 +551,9 @@ namespace Ryujinx.HLE.HOS
 
                     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);
                 }
@@ -654,7 +688,7 @@ namespace Ryujinx.HLE.HOS
             LoadSetAtPath(Path.Combine(home, ".switch"));
             LoadSetAtPath(Device.FileSystem.GetSystemPath());
 
-            KeySet = ExternalKeys.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile);
+            KeySet = ExternalKeyReader.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile);
 
             void LoadSetAtPath(string basePath)
             {

+ 24 - 10
Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs

@@ -1,6 +1,8 @@
 using LibHac;
 using LibHac.Fs;
-using LibHac.Fs.NcaUtils;
+using LibHac.FsSystem;
+using LibHac.FsSystem.NcaUtils;
+using LibHac.Spl;
 using Ryujinx.Common;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.Utilities;
@@ -25,7 +27,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
             try
             {
                 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)
                 {
@@ -111,13 +120,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
                     PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage());
 
                     ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet);
-                    
+
                     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)
                 {
@@ -130,15 +142,17 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
 
         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)));
                 }
             }
         }
     }
-}
+}

+ 13 - 51
Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IDirectory.cs

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

+ 11 - 51
Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFile.cs

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

+ 38 - 158
Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs

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

+ 7 - 17
Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs

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

+ 37 - 0
Ryujinx.HLE/HOS/Services/Fs/IDeviceOperator.cs

@@ -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;
+        }
+    }
+}

+ 42 - 4
Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs

@@ -1,6 +1,8 @@
 using LibHac;
 using LibHac.Fs;
-using LibHac.Fs.NcaUtils;
+using LibHac.FsService;
+using LibHac.FsSystem;
+using LibHac.FsSystem.NcaUtils;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy;
@@ -14,7 +16,12 @@ namespace Ryujinx.HLE.HOS.Services.Fs
     [Service("fsp-srv")]
     class IFileSystemProxy : IpcService
     {
-        public IFileSystemProxy(ServiceCtx context) { }
+        private LibHac.FsService.IFileSystemProxy _baseFileSystemProxy;
+
+        public IFileSystemProxy(ServiceCtx context)
+        {
+            _baseFileSystemProxy = context.Device.System.FsServer.CreateFileSystemProxyService();
+        }
 
         [Command(1)]
         // Initialize(u64, pid)
@@ -125,6 +132,23 @@ namespace Ryujinx.HLE.HOS.Services.Fs
             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)]
         // OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> saveDataFs
         public ResultCode OpenSaveDataFileSystem(ServiceCtx context)
@@ -184,14 +208,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs
             byte[]    padding   = context.RequestData.ReadBytes(7);
             long      titleId   = context.RequestData.ReadInt64();
 
-            ContentType contentType = ContentType.Data;
+            NcaContentType contentType = NcaContentType.Data;
 
             StorageId installedStorage =
                 context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId);
 
             if (installedStorage == StorageId.None)
             {
-                contentType = ContentType.PublicData;
+                contentType = NcaContentType.PublicData;
 
                 installedStorage =
                     context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId);
@@ -246,6 +270,20 @@ namespace Ryujinx.HLE.HOS.Services.Fs
             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)]
         // GetGlobalAccessLogMode() -> u32 logMode
         public ResultCode GetGlobalAccessLogMode(ServiceCtx context)

+ 21 - 21
Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs

@@ -1,4 +1,4 @@
-using LibHac.Fs.NcaUtils;
+using LibHac.FsSystem.NcaUtils;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.FileSystem.Content;
 using System.Text;
@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            if (ResolvePath(context, titleId, ContentType.Program))
+            if (ResolvePath(context, titleId, NcaContentType.Program))
             {
                 return ResultCode.Success;
             }
@@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            RedirectPath(context, titleId, 0, ContentType.Program);
+            RedirectPath(context, titleId, 0, NcaContentType.Program);
 
             return ResultCode.Success;
         }
@@ -49,7 +49,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            if (ResolvePath(context, titleId, ContentType.Control))
+            if (ResolvePath(context, titleId, NcaContentType.Control))
             {
                 return ResultCode.Success;
             }
@@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            if (ResolvePath(context, titleId, ContentType.Manual))
+            if (ResolvePath(context, titleId, NcaContentType.Manual))
             {
                 return ResultCode.Success;
             }
@@ -81,7 +81,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             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;
             }
@@ -97,7 +97,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            RedirectPath(context, titleId, 1, ContentType.Control);
+            RedirectPath(context, titleId, 1, NcaContentType.Control);
 
             return ResultCode.Success;
         }
@@ -108,7 +108,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            RedirectPath(context, titleId, 1, ContentType.Manual);
+            RedirectPath(context, titleId, 1, NcaContentType.Manual);
 
             return ResultCode.Success;
         }
@@ -119,7 +119,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            if (ResolvePath(context, titleId, ContentType.Manual))
+            if (ResolvePath(context, titleId, NcaContentType.Manual))
             {
                 return ResultCode.Success;
             }
@@ -135,7 +135,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            RedirectPath(context, titleId, 1, ContentType.Manual);
+            RedirectPath(context, titleId, 1, NcaContentType.Manual);
 
             return ResultCode.Success;
         }
@@ -155,7 +155,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            RedirectPath(context, titleId, 1, ContentType.Program);
+            RedirectPath(context, titleId, 1, NcaContentType.Program);
 
             return ResultCode.Success;
         }
@@ -175,7 +175,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            DeleteContentPath(context, titleId, ContentType.Program);
+            DeleteContentPath(context, titleId, NcaContentType.Program);
 
             return ResultCode.Success;
         }
@@ -186,7 +186,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            DeleteContentPath(context, titleId, ContentType.Control);
+            DeleteContentPath(context, titleId, NcaContentType.Control);
 
             return ResultCode.Success;
         }
@@ -197,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            DeleteContentPath(context, titleId, ContentType.Manual);
+            DeleteContentPath(context, titleId, NcaContentType.Manual);
 
             return ResultCode.Success;
         }
@@ -208,12 +208,12 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
         {
             long titleId = context.RequestData.ReadInt64();
 
-            DeleteContentPath(context, titleId, ContentType.Manual);
+            DeleteContentPath(context, titleId, NcaContentType.Manual);
 
             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);
             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);
         }
 
-        private bool ResolvePath(ServiceCtx context, long titleId,ContentType contentType)
+        private bool ResolvePath(ServiceCtx context, long titleId, NcaContentType contentType)
         {
             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))
             {
@@ -243,12 +243,12 @@ namespace Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager
             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;
-            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);
         }
     }
 }

+ 21 - 5
Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs

@@ -1,5 +1,7 @@
+using LibHac;
 using LibHac.Fs;
-using LibHac.Fs.NcaUtils;
+using LibHac.FsSystem;
+using LibHac.FsSystem.NcaUtils;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.HOS.SystemState;
@@ -165,7 +167,7 @@ namespace Ryujinx.HLE.HOS.Services.Settings
         public byte[] GetFirmwareData(Switch device)
         {
             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))
             {
@@ -185,11 +187,25 @@ namespace Ryujinx.HLE.HOS.Services.Settings
 
                 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;
+                }
+
+                result = firmwareFile.GetSize(out long fileSize);
+                if (result.IsFailure())
+                {
+                    return null;
+                }
 
-                byte[] data = new byte[firmwareFile.GetSize()];
+                byte[] data = new byte[fileSize];
 
-                firmwareFile.Read(data, 0);
+                result = firmwareFile.Read(out _, 0, data);
+                if (result.IsFailure())
+                {
+                    return null;
+                }
 
                 return data;
             }

+ 12 - 7
Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs

@@ -1,5 +1,7 @@
-using LibHac.Fs;
-using LibHac.Fs.NcaUtils;
+using LibHac;
+using LibHac.Fs;
+using LibHac.FsSystem;
+using LibHac.FsSystem.NcaUtils;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.FileSystem;
@@ -58,9 +60,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
                 {
                     Nca         nca              = new Nca(_device.System.KeySet, ncaFileStream);
                     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>();
 
@@ -139,7 +142,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
 
         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()
@@ -162,9 +165,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
             Nca         nca   = new Nca(_device.System.KeySet, ncaFile);
             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)

+ 1 - 1
Ryujinx.HLE/Ryujinx.HLE.csproj

@@ -48,7 +48,7 @@
 
   <ItemGroup>
     <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="TimeZoneConverter.Posix" Version="2.1.0" />
   </ItemGroup>

+ 1 - 1
Ryujinx/Configuration.cs

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

+ 24 - 14
Ryujinx/Ui/ApplicationLibrary.cs

@@ -1,6 +1,8 @@
 using LibHac;
 using LibHac.Fs;
-using LibHac.Fs.NcaUtils;
+using LibHac.FsSystem;
+using LibHac.FsSystem.NcaUtils;
+using LibHac.Spl;
 using Ryujinx.Common.Logging;
 using System;
 using System.Collections.Generic;
@@ -8,6 +10,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
+
 using SystemState = Ryujinx.HLE.HOS.SystemState;
 
 namespace Ryujinx.UI
@@ -115,8 +118,9 @@ namespace Ryujinx.UI
                             }
 
                             // Creates NACP class from the NACP file
-                            IFile controlNacp = controlFs.OpenFile("/control.nacp", OpenMode.Read);
-                            Nacp  controlData = new Nacp(controlNacp.AsStream());
+                            controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp", OpenMode.Read).ThrowIfFailure();
+
+                            Nacp controlData = new Nacp(controlNacpFile.AsStream());
 
                             // Get the title name, title ID, developer name and version number from the NACP
                             version = controlData.DisplayVersion;
@@ -150,7 +154,8 @@ namespace Ryujinx.UI
                             // Read the icon from the ControlFS and store it as a byte array
                             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())
                                 {
                                     icon.AsStream().CopyTo(stream);
@@ -159,15 +164,15 @@ namespace Ryujinx.UI
                             }
                             catch (HorizonResultException)
                             {
-                                IDirectory controlDir = controlFs.OpenDirectory("./", OpenDirectoryMode.All);
-                                foreach (DirectoryEntry entry in controlDir.Read())
+                                foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
                                 {
                                     if (entry.Name == "control.nacp")
                                     {
                                         continue;
                                     }
 
-                                    IFile icon = controlFs.OpenFile(entry.FullPath, OpenMode.Read);
+                                    controlFs.OpenFile(out IFile icon, entry.FullPath, OpenMode.Read).ThrowIfFailure();
+
                                     using (MemoryStream stream = new MemoryStream())
                                     {
                                         icon.AsStream().CopyTo(stream);
@@ -346,21 +351,26 @@ namespace Ryujinx.UI
             Nca controlNca = null;
 
             // 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
-            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());
-                if (nca.Header.ContentType == ContentType.Control)
+                Pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
+
+                Nca nca = new Nca(KeySet, ncaFile.AsStorage());
+
+                if (nca.Header.ContentType == NcaContentType.Control)
                 {
                     controlNca = nca;
                 }