using LibHac; using LibHac.FsSystem; using LibHac.Sf; using Ryujinx.Common.Logging; using Ryujinx.Common.Pools; using Ryujinx.HLE.HOS.Ipc; using System; using System.Threading.Tasks; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy { class IStorage : DisposableIpcService { private ReferenceCountedDisposable _baseStorage; public IStorage(ReferenceCountedDisposable baseStorage) { _baseStorage = baseStorage; } [CommandHipc(0)] // Read(u64 offset, u64 length) -> buffer buffer public ResultCode Read(ServiceCtx context) { ulong offset = context.RequestData.ReadUInt64(); ulong size = context.RequestData.ReadUInt64(); if (context.Request.ReceiveBuff.Count > 0) { IpcBuffDesc buffDesc = context.Request.ReceiveBuff[0]; // Use smaller length to avoid overflows. int actualSize = (int)Math.Min(size, 128 * 1024); using (PooledBuffer scratch = BufferPool.Rent(actualSize)) { ulong bytesRead = 0; Result result = Result.Success; while (bytesRead < size) { int thisReadSize = (int)Math.Min((long)actualSize, (long)(size - bytesRead)); result = _baseStorage.Target.Read((long)(offset + bytesRead), new OutBuffer(scratch.AsSpan), (long)thisReadSize); context.Memory.Write(buffDesc.Position + bytesRead, scratch.AsSpan.Slice(0, thisReadSize)); bytesRead += (ulong)thisReadSize; } return (ResultCode)result.Value; } } return ResultCode.Success; } [CommandHipc(4)] // GetSize() -> u64 size public ResultCode GetSize(ServiceCtx context) { Result result = _baseStorage.Target.GetSize(out long size); context.ResponseData.Write(size); return (ResultCode)result.Value; } protected override void Dispose(bool isDisposing) { if (isDisposing) { _baseStorage?.Dispose(); } } } }