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 System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
|
||||||
namespace LibHac.FsSrv.FsCreator;
|
namespace LibHac.FsSrv.FsCreator;
|
||||||
|
|
||||||
public interface IMemoryStorageCreator
|
public interface IMemoryStorageCreator
|
||||||
{
|
{
|
||||||
Result Create(out IStorage storage, out Memory<byte> buffer, int storageId);
|
public enum MemoryStorageId
|
||||||
Result RegisterBuffer(int storageId, Memory<byte> buffer);
|
{
|
||||||
|
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;
|
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
|
public interface INspRootFileSystemCreator
|
||||||
{
|
{
|
||||||
Result Create(ref SharedRef<IFileSystem> outFileSystem, ref readonly SharedRef<IStorage> baseStorage);
|
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