/ src / Ryujinx.HLE / HOS / HorizonFsClient.cs
HorizonFsClient.cs
  1  using LibHac.Common;
  2  using LibHac.Fs.Fsa;
  3  using LibHac.FsSystem;
  4  using LibHac.Ncm;
  5  using LibHac.Tools.FsSystem.NcaUtils;
  6  using Ryujinx.HLE.FileSystem;
  7  using Ryujinx.Horizon;
  8  using Ryujinx.Horizon.Common;
  9  using Ryujinx.Horizon.Sdk.Fs;
 10  using System;
 11  using System.Collections.Concurrent;
 12  using System.IO;
 13  
 14  namespace Ryujinx.HLE.HOS
 15  {
 16      class HorizonFsClient : IFsClient
 17      {
 18          private readonly Horizon _system;
 19          private readonly LibHac.Fs.FileSystemClient _fsClient;
 20          private readonly ConcurrentDictionary<string, LocalStorage> _mountedStorages;
 21  
 22          public HorizonFsClient(Horizon system)
 23          {
 24              _system = system;
 25              _fsClient = _system.LibHacHorizonManager.FsClient.Fs;
 26              _mountedStorages = new();
 27          }
 28  
 29          public void CloseFile(FileHandle handle)
 30          {
 31              _fsClient.CloseFile((LibHac.Fs.FileHandle)handle.Value);
 32          }
 33  
 34          public Result GetFileSize(out long size, FileHandle handle)
 35          {
 36              return _fsClient.GetFileSize(out size, (LibHac.Fs.FileHandle)handle.Value).ToHorizonResult();
 37          }
 38  
 39          public Result MountSystemData(string mountName, ulong dataId)
 40          {
 41              string contentPath = _system.ContentManager.GetInstalledContentPath(dataId, StorageId.BuiltInSystem, NcaContentType.PublicData);
 42              string installPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath);
 43  
 44              if (!string.IsNullOrWhiteSpace(installPath))
 45              {
 46                  string ncaPath = installPath;
 47  
 48                  if (File.Exists(ncaPath))
 49                  {
 50                      LocalStorage ncaStorage = null;
 51  
 52                      try
 53                      {
 54                          ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open);
 55  
 56                          Nca nca = new(_system.KeySet, ncaStorage);
 57  
 58                          using var ncaFileSystem = nca.OpenFileSystem(NcaSectionType.Data, _system.FsIntegrityCheckLevel);
 59                          using var ncaFsRef = new UniqueRef<IFileSystem>(ncaFileSystem);
 60  
 61                          Result result = _fsClient.Register(mountName.ToU8Span(), ref ncaFsRef.Ref).ToHorizonResult();
 62                          if (result.IsFailure)
 63                          {
 64                              ncaStorage.Dispose();
 65                          }
 66                          else
 67                          {
 68                              _mountedStorages.TryAdd(mountName, ncaStorage);
 69                          }
 70  
 71                          return result;
 72                      }
 73                      catch (HorizonResultException ex)
 74                      {
 75                          ncaStorage?.Dispose();
 76  
 77                          return ex.ResultValue.ToHorizonResult();
 78                      }
 79                  }
 80              }
 81  
 82              // TODO: Return correct result here, this is likely wrong.
 83  
 84              return LibHac.Fs.ResultFs.TargetNotFound.Handle().ToHorizonResult();
 85          }
 86  
 87          public Result OpenFile(out FileHandle handle, string path, OpenMode openMode)
 88          {
 89              var result = _fsClient.OpenFile(out var libhacHandle, path.ToU8Span(), (LibHac.Fs.OpenMode)openMode);
 90              handle = new(libhacHandle);
 91  
 92              return result.ToHorizonResult();
 93          }
 94  
 95          public Result QueryMountSystemDataCacheSize(out long size, ulong dataId)
 96          {
 97              // TODO.
 98  
 99              size = 0;
100  
101              return Result.Success;
102          }
103  
104          public Result ReadFile(FileHandle handle, long offset, Span<byte> destination)
105          {
106              return _fsClient.ReadFile((LibHac.Fs.FileHandle)handle.Value, offset, destination).ToHorizonResult();
107          }
108  
109          public void Unmount(string mountName)
110          {
111              if (_mountedStorages.TryRemove(mountName, out LocalStorage ncaStorage))
112              {
113                  ncaStorage.Dispose();
114              }
115  
116              _fsClient.Unmount(mountName.ToU8Span());
117          }
118      }
119  }