From 21c9c04f9f862d9c70c53dabe2f67bf1fb3d3f07 Mon Sep 17 00:00:00 2001
From: Alex Barney <thealexbarney@gmail.com>
Date: Wed, 25 Mar 2020 01:14:35 -0700
Subject: [PATCH] Add IMultiCommitManager (#1011)

* Update LibHac

* Add IMultiCommitManager

* Updates

* Delete NuGet.Config

* Add command version
---
 .../FileSystem/Content/ContentManager.cs      | 19 +++++-----
 Ryujinx.HLE/HOS/Font/SharedFontManager.cs     |  4 +-
 Ryujinx.HLE/HOS/Horizon.cs                    | 14 +++----
 .../FileSystemProxy/FileSystemProxyHelper.cs  |  5 ++-
 .../Fs/FileSystemProxy/IFileSystem.cs         | 38 +++++++++++--------
 .../HOS/Services/Fs/IFileSystemProxy.cs       | 14 +++++++
 .../HOS/Services/Fs/IMultiCommitManager.cs    | 35 +++++++++++++++++
 .../HOS/Services/Mii/MiiDatabaseManager.cs    |  5 ++-
 .../Settings/ISystemSettingsServer.cs         |  3 +-
 .../Time/TimeZone/TimeZoneContentManager.cs   |  5 ++-
 Ryujinx.HLE/Ryujinx.HLE.csproj                |  2 +-
 Ryujinx.HLE/Utilities/StringUtils.cs          | 13 ++++++-
 Ryujinx/Ui/ApplicationLibrary.cs              | 15 ++++----
 Ryujinx/Ui/GameTableContextMenu.cs            | 12 +++---
 Ryujinx/Ui/SaveImporter.cs                    |  6 +--
 15 files changed, 131 insertions(+), 59 deletions(-)
 create mode 100644 Ryujinx.HLE/HOS/Services/Fs/IMultiCommitManager.cs

diff --git a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
index 1c6364c7df..bb8b660945 100644
--- a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
+++ b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
@@ -1,4 +1,5 @@
 using LibHac;
+using LibHac.Common;
 using LibHac.Fs;
 using LibHac.FsSystem;
 using LibHac.FsSystem.NcaUtils;
@@ -491,11 +492,11 @@ namespace Ryujinx.HLE.FileSystem.Content
 
             if (filesystem.FileExists($"{path}/00"))
             {
-                filesystem.OpenFile(out file, $"{path}/00", mode);
+                filesystem.OpenFile(out file, $"{path}/00".ToU8Span(), mode);
             }
             else
             {
-                filesystem.OpenFile(out file, path, mode);
+                filesystem.OpenFile(out file, path.ToU8Span(), mode);
             }
 
             return file;
@@ -608,7 +609,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
                         string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
 
-                        if (fs.OpenFile(out IFile metaFile, cnmtPath, OpenMode.Read).IsSuccess())
+                        if (fs.OpenFile(out IFile metaFile, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess())
                         {
                             var meta = new Cnmt(metaFile.AsStream());
 
@@ -636,7 +637,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
                             var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
 
-                            if (romfs.OpenFile(out IFile systemVersionFile, "/file", OpenMode.Read).IsSuccess())
+                            if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
                             {
                                 systemVersion = new SystemVersion(systemVersionFile.AsStream());
                             }
@@ -673,7 +674,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
                                     string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
 
-                                    if (fs.OpenFile(out IFile metaFile, cnmtPath, OpenMode.Read).IsSuccess())
+                                    if (fs.OpenFile(out IFile metaFile, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess())
                                     {
                                         var meta = new Cnmt(metaFile.AsStream());
 
@@ -744,7 +745,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
                         string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
 
-                        if (fs.OpenFile(out IFile metaFile, cnmtPath, OpenMode.Read).IsSuccess())
+                        if (fs.OpenFile(out IFile metaFile, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess())
                         {
                             var meta = new Cnmt(metaFile.AsStream());
 
@@ -760,7 +761,7 @@ namespace Ryujinx.HLE.FileSystem.Content
                     {
                         var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
 
-                        if (romfs.OpenFile(out IFile systemVersionFile, "/file", OpenMode.Read).IsSuccess())
+                        if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
                         {
                             systemVersion = new SystemVersion(systemVersionFile.AsStream());
                         }
@@ -809,7 +810,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
                         string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
 
-                        if (fs.OpenFile(out IFile metaFile, cnmtPath, OpenMode.Read).IsSuccess())
+                        if (fs.OpenFile(out IFile metaFile, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess())
                         {
                             var meta = new Cnmt(metaFile.AsStream());
 
@@ -879,7 +880,7 @@ namespace Ryujinx.HLE.FileSystem.Content
                             {
                                 var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
 
-                                if (romfs.OpenFile(out IFile systemVersionFile, "/file", OpenMode.Read).IsSuccess())
+                                if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
                                 {
                                     return new SystemVersion(systemVersionFile.AsStream());
                                 }
diff --git a/Ryujinx.HLE/HOS/Font/SharedFontManager.cs b/Ryujinx.HLE/HOS/Font/SharedFontManager.cs
index c54c8194bc..0810e216aa 100644
--- a/Ryujinx.HLE/HOS/Font/SharedFontManager.cs
+++ b/Ryujinx.HLE/HOS/Font/SharedFontManager.cs
@@ -1,7 +1,7 @@
+using LibHac.Common;
 using LibHac.Fs;
 using LibHac.FsSystem;
 using LibHac.FsSystem.NcaUtils;
-using Ryujinx.Common;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.FileSystem.Content;
@@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Font
                                 Nca         nca          = new Nca(_device.System.KeySet, ncaFileStream);
                                 IFileSystem romfs        = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
 
-                                romfs.OpenFile(out IFile fontFile, "/" + fontFilename, OpenMode.Read).ThrowIfFailure();
+                                romfs.OpenFile(out IFile fontFile, ("/" + fontFilename).ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                                 data = DecryptFont(fontFile.AsStream());
                             }
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index e70a9e59ec..ee8c2a20e8 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -292,7 +292,7 @@ namespace Ryujinx.HLE.HOS
 
             foreach (DirectoryEntryEx ticketEntry in securePartition.EnumerateEntries("/", "*.tik"))
             {
-                Result result = securePartition.OpenFile(out IFile ticketFile, ticketEntry.FullPath, OpenMode.Read);
+                Result result = securePartition.OpenFile(out IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read);
 
                 if (result.IsSuccess())
                 {
@@ -304,7 +304,7 @@ namespace Ryujinx.HLE.HOS
 
             foreach (DirectoryEntryEx fileEntry in securePartition.EnumerateEntries("/", "*.nca"))
             {
-                Result result = securePartition.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read);
+                Result result = securePartition.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read);
                 if (result.IsFailure())
                 {
                     continue;
@@ -352,7 +352,7 @@ namespace Ryujinx.HLE.HOS
         {
             IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
 
-            Result result = controlFs.OpenFile(out IFile controlFile, "/control.nacp", OpenMode.Read);
+            Result result = controlFs.OpenFile(out IFile controlFile, "/control.nacp".ToU8Span(), OpenMode.Read);
 
             if (result.IsSuccess())
             {
@@ -393,7 +393,7 @@ namespace Ryujinx.HLE.HOS
 
             foreach (DirectoryEntryEx ticketEntry in nsp.EnumerateEntries("/", "*.tik"))
             {
-                Result result = nsp.OpenFile(out IFile ticketFile, ticketEntry.FullPath, OpenMode.Read);
+                Result result = nsp.OpenFile(out IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read);
 
                 if (result.IsSuccess())
                 {
@@ -409,7 +409,7 @@ namespace Ryujinx.HLE.HOS
 
             foreach (DirectoryEntryEx fileEntry in nsp.EnumerateEntries("/", "*.nca"))
             {
-                nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
+                nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                 Nca nca = new Nca(KeySet, ncaFile.AsStorage());
 
@@ -517,7 +517,7 @@ namespace Ryujinx.HLE.HOS
 
         private void LoadExeFs(IFileSystem codeFs, out Npdm metaData)
         {
-            Result result = codeFs.OpenFile(out IFile npdmFile, "/main.npdm", OpenMode.Read);
+            Result result = codeFs.OpenFile(out IFile npdmFile, "/main.npdm".ToU8Span(), OpenMode.Read);
 
             if (ResultFs.PathNotFound.Includes(result))
             {
@@ -543,7 +543,7 @@ namespace Ryujinx.HLE.HOS
 
                     Logger.PrintInfo(LogClass.Loader, $"Loading {file.Name}...");
 
-                    codeFs.OpenFile(out IFile nsoFile, file.FullPath, OpenMode.Read).ThrowIfFailure();
+                    codeFs.OpenFile(out IFile nsoFile, file.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                     NxStaticObject staticObject = new NxStaticObject(nsoFile.AsStream());
 
diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
index c0f28166b1..46151cbcfd 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/FileSystemProxyHelper.cs
@@ -1,4 +1,5 @@
 using LibHac;
+using LibHac.Common;
 using LibHac.Fs;
 using LibHac.FsSystem;
 using LibHac.FsSystem.NcaUtils;
@@ -81,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
 
                     string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\');
 
-                    Result result = nsp.OpenFile(out LibHac.Fs.IFile ncaFile, filename, OpenMode.Read);
+                    Result result = nsp.OpenFile(out LibHac.Fs.IFile ncaFile, filename.ToU8Span(), OpenMode.Read);
                     if (result.IsFailure())
                     {
                         return (ResultCode)result.Value;
@@ -102,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         {
             foreach (DirectoryEntryEx ticketEntry in nsp.EnumerateEntries("/", "*.tik"))
             {
-                Result result = nsp.OpenFile(out LibHac.Fs.IFile ticketFile, ticketEntry.FullPath, OpenMode.Read);
+                Result result = nsp.OpenFile(out LibHac.Fs.IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read);
 
                 if (result.IsSuccess())
                 {
diff --git a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs
index ed7ae0c178..b907e17a9f 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs
@@ -1,4 +1,5 @@
 using LibHac;
+using LibHac.Common;
 using LibHac.Fs;
 
 using static Ryujinx.HLE.Utilities.StringUtils;
@@ -14,11 +15,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
             _fileSystem = provider;
         }
 
+        public LibHac.Fs.IFileSystem GetBaseFileSystem()
+        {
+            return _fileSystem;
+        }
+
         [Command(0)]
         // CreateFile(u32 createOption, u64 size, buffer<bytes<0x301>, 0x19, 0x301> path)
         public ResultCode CreateFile(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             CreateFileOptions createOption = (CreateFileOptions)context.RequestData.ReadInt32();
             context.RequestData.BaseStream.Position += 4;
@@ -32,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // DeleteFile(buffer<bytes<0x301>, 0x19, 0x301> path)
         public ResultCode DeleteFile(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             return (ResultCode)_fileSystem.DeleteFile(name).Value;
         }
@@ -41,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // CreateDirectory(buffer<bytes<0x301>, 0x19, 0x301> path)
         public ResultCode CreateDirectory(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             return (ResultCode)_fileSystem.CreateDirectory(name).Value;
         }
@@ -50,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // DeleteDirectory(buffer<bytes<0x301>, 0x19, 0x301> path)
         public ResultCode DeleteDirectory(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             return (ResultCode)_fileSystem.DeleteDirectory(name).Value;
         }
@@ -59,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // DeleteDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path)
         public ResultCode DeleteDirectoryRecursively(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             return (ResultCode)_fileSystem.DeleteDirectoryRecursively(name).Value;
         }
@@ -68,8 +74,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // RenameFile(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath)
         public ResultCode RenameFile(ServiceCtx context)
         {
-            string oldName = ReadUtf8String(context, 0);
-            string newName = ReadUtf8String(context, 1);
+            U8Span oldName = ReadUtf8Span(context, 0);
+            U8Span newName = ReadUtf8Span(context, 1);
 
             return (ResultCode)_fileSystem.RenameFile(oldName, newName).Value;
         }
@@ -78,8 +84,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // RenameDirectory(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath)
         public ResultCode RenameDirectory(ServiceCtx context)
         {
-            string oldName = ReadUtf8String(context, 0);
-            string newName = ReadUtf8String(context, 1);
+            U8Span oldName = ReadUtf8Span(context, 0);
+            U8Span newName = ReadUtf8Span(context, 1);
 
             return (ResultCode)_fileSystem.RenameDirectory(oldName, newName).Value;
         }
@@ -88,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // GetEntryType(buffer<bytes<0x301>, 0x19, 0x301> path) -> nn::fssrv::sf::DirectoryEntryType
         public ResultCode GetEntryType(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             Result result = _fileSystem.GetEntryType(out DirectoryEntryType entryType, name);
 
@@ -103,7 +109,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         {
             OpenMode mode = (OpenMode)context.RequestData.ReadInt32();
 
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             Result result = _fileSystem.OpenFile(out LibHac.Fs.IFile file, name, mode);
 
@@ -123,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         {
             OpenDirectoryMode mode = (OpenDirectoryMode)context.RequestData.ReadInt32();
 
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             Result result = _fileSystem.OpenDirectory(out LibHac.Fs.IDirectory dir, name, mode);
 
@@ -148,7 +154,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // GetFreeSpaceSize(buffer<bytes<0x301>, 0x19, 0x301> path) -> u64 totalFreeSpace
         public ResultCode GetFreeSpaceSize(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             Result result = _fileSystem.GetFreeSpaceSize(out long size, name);
 
@@ -161,7 +167,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // GetTotalSpaceSize(buffer<bytes<0x301>, 0x19, 0x301> path) -> u64 totalSize
         public ResultCode GetTotalSpaceSize(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             Result result = _fileSystem.GetTotalSpaceSize(out long size, name);
 
@@ -174,7 +180,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // CleanDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path)
         public ResultCode CleanDirectoryRecursively(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             return (ResultCode)_fileSystem.CleanDirectoryRecursively(name).Value;
         }
@@ -183,7 +189,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
         // GetFileTimeStampRaw(buffer<bytes<0x301>, 0x19, 0x301> path) -> bytes<0x20> timestamp
         public ResultCode GetFileTimeStampRaw(ServiceCtx context)
         {
-            string name = ReadUtf8String(context);
+            U8Span name = ReadUtf8Span(context);
 
             Result result = _fileSystem.GetFileTimeStampRaw(out FileTimeStampRaw timestamp, name);
 
diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
index 43ae80aa08..537882f1ec 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
@@ -513,5 +513,19 @@ namespace Ryujinx.HLE.HOS.Services.Fs
 
             return ResultCode.Success;
         }
+
+        [Command(1200)] // 6.0.0+
+        // OpenMultiCommitManager() -> object<nn::fssrv::sf::IMultiCommitManager>
+        public ResultCode OpenMultiCommitManager(ServiceCtx context)
+        {
+            Result result = _baseFileSystemProxy.OpenMultiCommitManager(out LibHac.FsService.IMultiCommitManager commitManager);
+
+            if (result.IsSuccess())
+            {
+                MakeObject(context, new IMultiCommitManager(commitManager));
+            }
+
+            return (ResultCode)result.Value;
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Fs/IMultiCommitManager.cs b/Ryujinx.HLE/HOS/Services/Fs/IMultiCommitManager.cs
new file mode 100644
index 0000000000..c26f54b690
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Fs/IMultiCommitManager.cs
@@ -0,0 +1,35 @@
+using LibHac;
+using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy;
+
+namespace Ryujinx.HLE.HOS.Services.Fs
+{
+    class IMultiCommitManager : IpcService // 6.0.0+
+    {
+        private LibHac.FsService.IMultiCommitManager _baseCommitManager;
+
+        public IMultiCommitManager(LibHac.FsService.IMultiCommitManager baseCommitManager)
+        {
+            _baseCommitManager = baseCommitManager;
+        }
+
+        [Command(1)] // 6.0.0+
+        // Add(object<nn::fssrv::sf::IFileSystem>)
+        public ResultCode Add(ServiceCtx context)
+        {
+            IFileSystem fileSystem = GetObject<IFileSystem>(context, 0);
+
+            Result result = _baseCommitManager.Add(fileSystem.GetBaseFileSystem());
+
+            return (ResultCode)result.Value;
+        }
+
+        [Command(2)] // 6.0.0+
+        // Commit()
+        public ResultCode Commit(ServiceCtx context)
+        {
+            Result result = _baseCommitManager.Commit();
+
+            return (ResultCode)result.Value;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs b/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs
index 6ba1b2bf9d..fcb254ffdf 100644
--- a/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs
@@ -17,8 +17,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii
         private const ulong  DatabaseSaveDataId     = 0x8000000000000030;
         private const ulong  NsTitleId              = 0x010000000000001F;
         private const ulong  SdbTitleId             = 0x0100000000000039;
-        private const string DatabasePath           = "mii:/MiiDatabase.dat";
-        private const string MountName              = "mii";
+
+        private static U8String DatabasePath = new U8String("mii:/MiiDatabase.dat");
+        private static U8String MountName    = new U8String("mii");
 
         private NintendoFigurineDatabase _database;
         private bool                     _isDirty;
diff --git a/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs b/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs
index 73f437e8bf..108cb56f7c 100644
--- a/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs
@@ -1,4 +1,5 @@
 using LibHac;
+using LibHac.Common;
 using LibHac.Fs;
 using LibHac.FsSystem;
 using LibHac.FsSystem.NcaUtils;
@@ -231,7 +232,7 @@ namespace Ryujinx.HLE.HOS.Services.Settings
 
                 IFileSystem firmwareRomFs = firmwareContent.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel);
 
-                Result result = firmwareRomFs.OpenFile(out IFile firmwareFile, "/file", OpenMode.Read);
+                Result result = firmwareRomFs.OpenFile(out IFile firmwareFile, "/file".ToU8Span(), OpenMode.Read);
                 if (result.IsFailure())
                 {
                     return null;
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
index f48452f31a..06d34e79ba 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
@@ -1,4 +1,5 @@
 using LibHac;
+using LibHac.Common;
 using LibHac.Fs;
 using LibHac.FsSystem;
 using LibHac.FsSystem.NcaUtils;
@@ -61,7 +62,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
                     Nca         nca              = new Nca(_device.System.KeySet, ncaFileStream);
                     IFileSystem romfs            = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
 
-                    romfs.OpenFile(out IFile binaryListFile, "/binaryList.txt", OpenMode.Read).ThrowIfFailure();
+                    romfs.OpenFile(out IFile binaryListFile, "/binaryList.txt".ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                     StreamReader reader = new StreamReader(binaryListFile.AsStream());
 
@@ -165,7 +166,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
             Nca         nca   = new Nca(_device.System.KeySet, ncaFile);
             IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
 
-            Result result = romfs.OpenFile(out IFile timeZoneBinaryFile, $"/zoneinfo/{locationName}", OpenMode.Read);
+            Result result = romfs.OpenFile(out IFile timeZoneBinaryFile, $"/zoneinfo/{locationName}".ToU8Span(), OpenMode.Read);
 
             timeZoneBinaryStream = timeZoneBinaryFile.AsStream();
 
diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj
index 01c29fbab3..367d7218f4 100644
--- a/Ryujinx.HLE/Ryujinx.HLE.csproj
+++ b/Ryujinx.HLE/Ryujinx.HLE.csproj
@@ -52,7 +52,7 @@
 
   <ItemGroup>
     <PackageReference Include="Concentus" Version="1.1.7" />
-    <PackageReference Include="LibHac" Version="0.9.0" />
+    <PackageReference Include="LibHac" Version="0.10.0" />
     <PackageReference Include="MsgPack.Cli" Version="1.0.1" />
     <PackageReference Include="TimeZoneConverter.Posix" Version="2.1.0" />
   </ItemGroup>
diff --git a/Ryujinx.HLE/Utilities/StringUtils.cs b/Ryujinx.HLE/Utilities/StringUtils.cs
index 4ce0823c11..f23a843f1a 100644
--- a/Ryujinx.HLE/Utilities/StringUtils.cs
+++ b/Ryujinx.HLE/Utilities/StringUtils.cs
@@ -1,4 +1,5 @@
-using Ryujinx.HLE.HOS;
+using LibHac.Common;
+using Ryujinx.HLE.HOS;
 using System;
 using System.Globalization;
 using System.IO;
@@ -73,6 +74,16 @@ namespace Ryujinx.HLE.Utilities
             }
         }
 
+        public static U8Span ReadUtf8Span(ServiceCtx context, int index = 0)
+        {
+            ulong position = (ulong)context.Request.PtrBuff[index].Position;
+            ulong size = (ulong)context.Request.PtrBuff[index].Size;
+
+            ReadOnlySpan<byte> buffer = context.Memory.GetSpan(position, size);
+
+            return new U8Span(buffer);
+        }
+
         public static string ReadUtf8StringSend(ServiceCtx context, int index = 0)
         {
             long position = context.Request.SendBuff[index].Position;
diff --git a/Ryujinx/Ui/ApplicationLibrary.cs b/Ryujinx/Ui/ApplicationLibrary.cs
index 6cf2a608c1..fc3d6122bb 100644
--- a/Ryujinx/Ui/ApplicationLibrary.cs
+++ b/Ryujinx/Ui/ApplicationLibrary.cs
@@ -1,5 +1,6 @@
 using JsonPrettyPrinterPlus;
 using LibHac;
+using LibHac.Common;
 using LibHac.Fs;
 using LibHac.Fs.Shim;
 using LibHac.FsSystem;
@@ -116,7 +117,7 @@ namespace Ryujinx.Ui
                                     {
                                         if (Path.GetExtension(fileEntry.FullPath).ToLower() == ".nca")
                                         {
-                                            pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
+                                            pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                                             Nca nca       = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
                                             int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
@@ -146,7 +147,7 @@ namespace Ryujinx.Ui
                                 {
                                     applicationIcon = _nspIcon;
 
-                                    Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm", OpenMode.Read);
+                                    Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm".ToU8Span(), OpenMode.Read);
 
                                     if (ResultFs.PathNotFound.Includes(result))
                                     {
@@ -162,7 +163,7 @@ namespace Ryujinx.Ui
                                     GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out titleId);
 
                                     // Creates NACP class from the NACP file
-                                    controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp", OpenMode.Read).ThrowIfFailure();
+                                    controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                                     Nacp controlData = new Nacp(controlNacpFile.AsStream());
 
@@ -174,7 +175,7 @@ namespace Ryujinx.Ui
                                     // Read the icon from the ControlFS and store it as a byte array
                                     try
                                     {
-                                        controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat", OpenMode.Read).ThrowIfFailure();
+                                        controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                                         using (MemoryStream stream = new MemoryStream())
                                         {
@@ -191,7 +192,7 @@ namespace Ryujinx.Ui
                                                 continue;
                                             }
 
-                                            controlFs.OpenFile(out IFile icon, entry.FullPath, OpenMode.Read).ThrowIfFailure();
+                                            controlFs.OpenFile(out IFile icon, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                                             using (MemoryStream stream = new MemoryStream())
                                             {
@@ -429,7 +430,7 @@ namespace Ryujinx.Ui
             // Add keys to key set if needed
             foreach (DirectoryEntryEx ticketEntry in pfs.EnumerateEntries("/", "*.tik"))
             {
-                Result result = pfs.OpenFile(out IFile ticketFile, ticketEntry.FullPath, OpenMode.Read);
+                Result result = pfs.OpenFile(out IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read);
 
                 if (result.IsSuccess())
                 {
@@ -442,7 +443,7 @@ namespace Ryujinx.Ui
             // Find the Control NCA and store it in variable called controlNca
             foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
             {
-                pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
+                pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                 Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
 
diff --git a/Ryujinx/Ui/GameTableContextMenu.cs b/Ryujinx/Ui/GameTableContextMenu.cs
index 6cddb9676e..8c0bd0bc64 100644
--- a/Ryujinx/Ui/GameTableContextMenu.cs
+++ b/Ryujinx/Ui/GameTableContextMenu.cs
@@ -208,7 +208,7 @@ namespace Ryujinx.Ui
 
                             foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
                             {
-                                pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
+                                pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
 
                                 Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
 
@@ -292,8 +292,8 @@ namespace Ryujinx.Ui
                             }
                         }
 
-                        fsClient.Unmount(source);
-                        fsClient.Unmount(output);
+                        fsClient.Unmount(source.ToU8Span());
+                        fsClient.Unmount(output.ToU8Span());
                     }
                 });
 
@@ -305,7 +305,7 @@ namespace Ryujinx.Ui
 
         private (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath)
         {
-            Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All);
+            Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath.ToU8Span(), OpenDirectoryMode.All);
             if (rc.IsFailure()) return (rc, false);
 
             using (sourceHandle)
@@ -346,12 +346,12 @@ namespace Ryujinx.Ui
 
         public Result CopyFile(FileSystemClient fs, string sourcePath, string destPath)
         {
-            Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read);
+            Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath.ToU8Span(), OpenMode.Read);
             if (rc.IsFailure()) return rc;
 
             using (sourceHandle)
             {
-                rc = fs.OpenFile(out FileHandle destHandle, destPath, OpenMode.Write | OpenMode.AllowAppend);
+                rc = fs.OpenFile(out FileHandle destHandle, destPath.ToU8Span(), OpenMode.Write | OpenMode.AllowAppend);
                 if (rc.IsFailure()) return rc;
 
                 using (destHandle)
diff --git a/Ryujinx/Ui/SaveImporter.cs b/Ryujinx/Ui/SaveImporter.cs
index 467cc4161d..4e02d200d8 100644
--- a/Ryujinx/Ui/SaveImporter.cs
+++ b/Ryujinx/Ui/SaveImporter.cs
@@ -78,18 +78,18 @@ namespace Ryujinx.Ui
                 result = fs.CopyDirectory("OldSave:/", "NewSave:/");
                 if (result.IsFailure()) return result;
 
-                result = fs.Commit("NewSave");
+                result = fs.Commit("NewSave".ToU8Span());
             }
             finally
             {
                 if (isOldMounted)
                 {
-                    fs.Unmount("OldSave");
+                    fs.Unmount("OldSave".ToU8Span());
                 }
 
                 if (isNewMounted)
                 {
-                    fs.Unmount("NewSave");
+                    fs.Unmount("NewSave".ToU8Span());
                 }
             }