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 }