mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Implement MemoryStorageCreator and NspRootFileSystemCreator
This commit is contained in:
parent
3f845e2964
commit
dc6f4fa489
5 changed files with 205 additions and 2 deletions
|
@ -93,3 +93,91 @@ public class MemoryStorage : IStorage
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows interacting with a <see cref="Memory{T}"/> via the <see cref="IStorage"/> interface.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 16.2.0 (FS 16.0.0)</remarks>
|
||||
internal class MemoryStorageFromMemory : IStorage
|
||||
{
|
||||
private Memory<byte> _buffer;
|
||||
private int _size;
|
||||
|
||||
public MemoryStorageFromMemory(Memory<byte> buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = buffer.Length;
|
||||
}
|
||||
|
||||
public MemoryStorageFromMemory(Memory<byte> buffer, int size)
|
||||
{
|
||||
Assert.SdkRequiresInRange(size, 0, buffer.Length);
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
Abort.DoAbortUnless(0 <= size && size < buffer.Length);
|
||||
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
}
|
||||
|
||||
public override Result Read(long offset, Span<byte> destination)
|
||||
{
|
||||
if (destination.Length == 0)
|
||||
return Result.Success;
|
||||
|
||||
Result res = CheckAccessRange(offset, destination.Length, _size);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
_buffer.Span.Slice((int)offset, destination.Length).CopyTo(destination);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result Write(long offset, ReadOnlySpan<byte> source)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
return Result.Success;
|
||||
|
||||
Result res = CheckAccessRange(offset, source.Length, _size);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
source.CopyTo(_buffer.Span.Slice((int)offset));
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result Flush()
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result SetSize(long size)
|
||||
{
|
||||
return ResultFs.UnsupportedSetSizeForMemoryStorage.Log();
|
||||
}
|
||||
|
||||
public override Result GetSize(out long size)
|
||||
{
|
||||
size = _size;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
||||
ReadOnlySpan<byte> inBuffer)
|
||||
{
|
||||
switch (operationId)
|
||||
{
|
||||
case OperationId.InvalidateCache:
|
||||
return Result.Success;
|
||||
case OperationId.QueryRange:
|
||||
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
Unsafe.As<byte, QueryRangeInfo>(ref MemoryMarshal.GetReference(outBuffer)).Clear();
|
||||
return Result.Success;
|
||||
default:
|
||||
return ResultFs.UnsupportedOperateRangeForMemoryStorage.Log();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,20 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
|
||||
public interface IMemoryStorageCreator
|
||||
{
|
||||
Result Create(out IStorage storage, out Memory<byte> buffer, int storageId);
|
||||
Result RegisterBuffer(int storageId, Memory<byte> buffer);
|
||||
public enum MemoryStorageId
|
||||
{
|
||||
UserPartitionFatFs,
|
||||
SignedSystemPartitionRaw,
|
||||
SystemPartitionFatFs,
|
||||
Id4,
|
||||
Count
|
||||
}
|
||||
|
||||
Result Create(ref SharedRef<IStorage> outStorage, out Memory<byte> outBuffer, MemoryStorageId id);
|
||||
Result RegisterBuffer(MemoryStorageId id, Memory<byte> buffer);
|
||||
}
|
|
@ -4,6 +4,10 @@ using LibHac.Fs.Fsa;
|
|||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IFileSystem"/> from an <see cref="IStorage"/> containing a partition filesystem of version 0 or version 1.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 18.3.0 (FS 18.0.0)</remarks>
|
||||
public interface INspRootFileSystemCreator
|
||||
{
|
||||
Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly SharedRef<IStorage> baseStorage);
|
||||
|
|
78
src/LibHac/FsSrv/FsCreator/MemoryStorageCreator.cs
Normal file
78
src/LibHac/FsSrv/FsCreator/MemoryStorageCreator.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Os;
|
||||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
|
||||
/// <summary>
|
||||
/// Creates <see cref="MemoryStorage"/>s from registered memory buffers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Used for in-memory System and User partitions when booting in safe mode.
|
||||
/// On startup, FS registers buffers which can be used later if needed.</para>
|
||||
/// <para>Based on nnSdk 18.3.0 (FS 18.0.0)</para>
|
||||
/// </remarks>
|
||||
public class MemoryStorageCreator : IMemoryStorageCreator
|
||||
{
|
||||
private SdkMutexType _mutex;
|
||||
private Array4<Buffer> _bufferArray;
|
||||
|
||||
private struct Buffer
|
||||
{
|
||||
public Memory<byte> MemoryBuffer;
|
||||
public bool IsInUse; // Each registered buffer can only be used to create a MemoryStorage a single time
|
||||
|
||||
public Buffer()
|
||||
{
|
||||
MemoryBuffer = default;
|
||||
IsInUse = false;
|
||||
}
|
||||
}
|
||||
|
||||
public MemoryStorageCreator()
|
||||
{
|
||||
_mutex = new SdkMutexType();
|
||||
|
||||
for (int i = 0; i < _bufferArray.Length; i++)
|
||||
{
|
||||
_bufferArray[i] = new Buffer();
|
||||
}
|
||||
}
|
||||
|
||||
public Result Create(ref SharedRef<IStorage> outStorage, out Memory<byte> outBuffer, IMemoryStorageCreator.MemoryStorageId id)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outBuffer);
|
||||
|
||||
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
ref Buffer buffer = ref _bufferArray[(int)id];
|
||||
|
||||
if (buffer.IsInUse)
|
||||
return ResultFs.AllocationMemoryFailed.Log();
|
||||
|
||||
if (buffer.MemoryBuffer.IsEmpty)
|
||||
return ResultFs.AllocationMemoryFailed.Log();
|
||||
|
||||
using var storage = new SharedRef<MemoryStorageFromMemory>(new MemoryStorageFromMemory(buffer.MemoryBuffer));
|
||||
buffer.MemoryBuffer.Span.Clear();
|
||||
|
||||
outStorage.SetByMove(ref storage.Ref);
|
||||
outBuffer = buffer.MemoryBuffer;
|
||||
buffer.IsInUse = true;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result RegisterBuffer(IMemoryStorageCreator.MemoryStorageId id, Memory<byte> buffer)
|
||||
{
|
||||
Assert.SdkAssert(id < IMemoryStorageCreator.MemoryStorageId.Count);
|
||||
Assert.SdkAssert(_bufferArray[(int)id].MemoryBuffer.IsEmpty);
|
||||
|
||||
_bufferArray[(int)id].MemoryBuffer = buffer;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
23
src/LibHac/FsSrv/FsCreator/NspRootFileSystemCreator.cs
Normal file
23
src/LibHac/FsSrv/FsCreator/NspRootFileSystemCreator.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
|
||||
/// <inheritdoc cref="INspRootFileSystemCreator"/>
|
||||
public class NspRootFileSystemCreator : INspRootFileSystemCreator
|
||||
{
|
||||
public Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly SharedRef<IStorage> baseStorage)
|
||||
{
|
||||
using var nspFs = new SharedRef<NintendoSubmissionPackageRootFileSystem>(new NintendoSubmissionPackageRootFileSystem());
|
||||
if (!nspFs.HasValue)
|
||||
return ResultFs.AllocationMemoryFailedInPartitionFileSystemCreatorA.Log();
|
||||
|
||||
Result res = nspFs.Get.Initialize(in baseStorage);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outFileSystem.SetByMove(ref nspFs.Ref);
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue