Ryujinx/src/Ryujinx.HLE/HOS/HorizonFsClient.cs
gdkchan 01c2b8097c
Implement NGC service (#5681)
* Implement NGC service

* Use raw byte arrays instead of string for _wordSeparators

* Silence IDE0230 for _wordSeparators

* Try to silence warning about _rangeValuesCount not being read on SparseSet

* Make AcType enum private

* Add abstract methods and one TODO that I forgot

* PR feedback

* More PR feedback

* More PR feedback
2023-09-27 19:21:26 +02:00

119 lines
3.9 KiB
C#

using LibHac.Common;
using LibHac.Fs.Fsa;
using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.HLE.FileSystem;
using Ryujinx.Horizon;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Fs;
using System;
using System.Collections.Concurrent;
using System.IO;
namespace Ryujinx.HLE.HOS
{
class HorizonFsClient : IFsClient
{
private readonly Horizon _system;
private readonly LibHac.Fs.FileSystemClient _fsClient;
private readonly ConcurrentDictionary<string, LocalStorage> _mountedStorages;
public HorizonFsClient(Horizon system)
{
_system = system;
_fsClient = _system.LibHacHorizonManager.FsClient.Fs;
_mountedStorages = new();
}
public void CloseFile(FileHandle handle)
{
_fsClient.CloseFile((LibHac.Fs.FileHandle)handle.Value);
}
public Result GetFileSize(out long size, FileHandle handle)
{
return _fsClient.GetFileSize(out size, (LibHac.Fs.FileHandle)handle.Value).ToHorizonResult();
}
public Result MountSystemData(string mountName, ulong dataId)
{
string contentPath = _system.ContentManager.GetInstalledContentPath(dataId, StorageId.BuiltInSystem, NcaContentType.PublicData);
string installPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(installPath))
{
string ncaPath = installPath;
if (File.Exists(ncaPath))
{
LocalStorage ncaStorage = null;
try
{
ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open);
Nca nca = new(_system.KeySet, ncaStorage);
using var ncaFileSystem = nca.OpenFileSystem(NcaSectionType.Data, _system.FsIntegrityCheckLevel);
using var ncaFsRef = new UniqueRef<IFileSystem>(ncaFileSystem);
Result result = _fsClient.Register(mountName.ToU8Span(), ref ncaFsRef.Ref).ToHorizonResult();
if (result.IsFailure)
{
ncaStorage.Dispose();
}
else
{
_mountedStorages.TryAdd(mountName, ncaStorage);
}
return result;
}
catch (HorizonResultException ex)
{
ncaStorage?.Dispose();
return ex.ResultValue.ToHorizonResult();
}
}
}
// TODO: Return correct result here, this is likely wrong.
return LibHac.Fs.ResultFs.TargetNotFound.Handle().ToHorizonResult();
}
public Result OpenFile(out FileHandle handle, string path, OpenMode openMode)
{
var result = _fsClient.OpenFile(out var libhacHandle, path.ToU8Span(), (LibHac.Fs.OpenMode)openMode);
handle = new(libhacHandle);
return result.ToHorizonResult();
}
public Result QueryMountSystemDataCacheSize(out long size, ulong dataId)
{
// TODO.
size = 0;
return Result.Success;
}
public Result ReadFile(FileHandle handle, long offset, Span<byte> destination)
{
return _fsClient.ReadFile((LibHac.Fs.FileHandle)handle.Value, offset, destination).ToHorizonResult();
}
public void Unmount(string mountName)
{
if (_mountedStorages.TryRemove(mountName, out LocalStorage ncaStorage))
{
ncaStorage.Dispose();
}
_fsClient.Unmount(mountName.ToU8Span());
}
}
}