mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Add RegisterProgramIndexMapInfo shim and tests
This commit is contained in:
parent
6496a2c1bc
commit
1f25b87d20
29
src/LibHac/Fs/Shim/ProgramIndexMapInfo.cs
Normal file
29
src/LibHac/Fs/Shim/ProgramIndexMapInfo.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.FsSrv;
|
||||
|
||||
namespace LibHac.Fs.Shim
|
||||
{
|
||||
public static class ProgramIndexMapInfoShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Unregisters any previously registered program index map info and registers the provided map info.
|
||||
/// </summary>
|
||||
/// <param name="fs">The <see cref="FileSystemClient"/> to use.</param>
|
||||
/// <param name="mapInfo">The program index map info entries to register.</param>
|
||||
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
|
||||
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.</returns>
|
||||
public static Result RegisterProgramIndexMapInfo(this FileSystemClient fs,
|
||||
ReadOnlySpan<ProgramIndexMapInfo> mapInfo)
|
||||
{
|
||||
if (mapInfo.IsEmpty)
|
||||
return Result.Success;
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
ReadOnlySpan<byte> mapInfoBuffer = MemoryMarshal.Cast<ProgramIndexMapInfo, byte>(mapInfo);
|
||||
|
||||
return fsProxy.RegisterProgramIndexMapInfo(mapInfoBuffer, mapInfo.Length);
|
||||
}
|
||||
}
|
||||
}
|
@ -512,7 +512,7 @@ namespace LibHac.FsSrv.Impl
|
||||
public bool CanWrite => ((_value >> 1) & 1) == 1;
|
||||
}
|
||||
|
||||
internal readonly struct AccessControlBits
|
||||
public readonly struct AccessControlBits
|
||||
{
|
||||
public readonly ulong Value;
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
using System.Threading;
|
||||
using LibHac.Bcat;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Os;
|
||||
using LibHac.Sm;
|
||||
|
||||
@ -12,6 +16,7 @@ namespace LibHac
|
||||
private const int InitialProcessCountMax = 0x50;
|
||||
internal ITimeSpanGenerator Time { get; }
|
||||
internal ServiceManager ServiceManager { get; }
|
||||
private HorizonClient LoaderClient { get; }
|
||||
|
||||
// long instead of ulong because the ulong Interlocked.Increment overload
|
||||
// wasn't added until .NET 5
|
||||
@ -29,6 +34,8 @@ namespace LibHac
|
||||
new FileSystemServer(CreatePrivilegedHorizonClient(), fsServerConfig);
|
||||
new BcatServer(CreateHorizonClient());
|
||||
// ReSharper restore ObjectCreationAsStatement
|
||||
|
||||
LoaderClient = CreatePrivilegedHorizonClient();
|
||||
}
|
||||
|
||||
public HorizonClient CreatePrivilegedHorizonClient()
|
||||
@ -50,5 +57,25 @@ namespace LibHac
|
||||
|
||||
return new HorizonClient(this, new ProcessId(processId));
|
||||
}
|
||||
|
||||
public HorizonClient CreateHorizonClient(ProgramId programId, AccessControlBits.Bits fsPermissions)
|
||||
{
|
||||
HorizonClient client = CreateHorizonClient();
|
||||
|
||||
var dataHeader = new AccessControlDataHeader();
|
||||
var descriptor = new AccessControlDescriptor();
|
||||
|
||||
descriptor.Version = 1;
|
||||
dataHeader.Version = 1;
|
||||
|
||||
descriptor.AccessFlags = (ulong)fsPermissions;
|
||||
dataHeader.AccessFlags = (ulong)fsPermissions;
|
||||
|
||||
LoaderClient.Fs.RegisterProgram(client.ProcessId.Value, programId, StorageId.BuiltInUser,
|
||||
SpanHelpers.AsReadOnlyByteSpan(in dataHeader), SpanHelpers.AsReadOnlyByteSpan(in descriptor))
|
||||
.ThrowIfFailure();
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
192
tests/LibHac.Tests/FsSrv/ProgramIndexMapInfoTests.cs
Normal file
192
tests/LibHac.Tests/FsSrv/ProgramIndexMapInfoTests.cs
Normal file
@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.Ncm;
|
||||
using Xunit;
|
||||
|
||||
namespace LibHac.Tests.FsSrv
|
||||
{
|
||||
public class ProgramIndexMapInfoTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetProgramIndexForAccessLog_IsMultiProgram_ReturnsCorrectIndex()
|
||||
{
|
||||
const int count = 7;
|
||||
|
||||
Horizon hos = HorizonFactory.CreateBasicHorizon();
|
||||
|
||||
var programs = new HorizonClient[count];
|
||||
|
||||
programs[0] = hos.CreateHorizonClient(new ProgramId(1), AccessControlBits.Bits.RegisterProgramIndexMapInfo);
|
||||
|
||||
for (int i = 1; i < programs.Length; i++)
|
||||
{
|
||||
programs[i] = hos.CreateHorizonClient(new ProgramId((ulong)(i + 1)), AccessControlBits.Bits.None);
|
||||
}
|
||||
|
||||
var map = new ProgramIndexMapInfo[count];
|
||||
|
||||
for (int i = 0; i < map.Length; i++)
|
||||
{
|
||||
map[i].MainProgramId = new ProgramId(1);
|
||||
map[i].ProgramId = new ProgramId((ulong)(i + 1));
|
||||
map[i].ProgramIndex = (byte)i;
|
||||
}
|
||||
|
||||
Assert.Success(programs[0].Fs.RegisterProgramIndexMapInfo(map));
|
||||
|
||||
for (int i = 0; i < programs.Length; i++)
|
||||
{
|
||||
Assert.Success(programs[i].Fs.GetFileSystemProxyServiceObject()
|
||||
.GetProgramIndexForAccessLog(out int programIndex, out int programCount));
|
||||
|
||||
Assert.Equal(i, programIndex);
|
||||
Assert.Equal(count, programCount);
|
||||
}
|
||||
}
|
||||
|
||||
private ProgramIndexMapInfoManager CreatePopulatedManager(int count, Func<int, long> idCreator)
|
||||
{
|
||||
var manager = new ProgramIndexMapInfoManager();
|
||||
|
||||
var map = new ProgramIndexMapInfo[count];
|
||||
|
||||
for (int i = 0; i < map.Length; i++)
|
||||
{
|
||||
map[i].MainProgramId = new ProgramId((ulong)idCreator(0));
|
||||
map[i].ProgramId = new ProgramId((ulong)idCreator(i));
|
||||
map[i].ProgramIndex = (byte)i;
|
||||
}
|
||||
|
||||
Assert.Success(manager.Reset(map));
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Get_IdDoesNotExist_ReturnsNull()
|
||||
{
|
||||
const int count = 5;
|
||||
|
||||
ProgramIndexMapInfoManager manager = CreatePopulatedManager(count, x => x + 3);
|
||||
|
||||
Assert.Null(manager.Get(new ProgramId(0)));
|
||||
Assert.Null(manager.Get(new ProgramId(2)));
|
||||
Assert.Null(manager.Get(new ProgramId(8)));
|
||||
Assert.Null(manager.Get(new ProgramId(9001)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Get_IdExists_ReturnsCorrectMapInfo()
|
||||
{
|
||||
const int count = 5;
|
||||
|
||||
ProgramIndexMapInfoManager manager = CreatePopulatedManager(count, x => x + 1);
|
||||
|
||||
// ReSharper disable PossibleInvalidOperationException
|
||||
ProgramIndexMapInfo? map = manager.Get(new ProgramId(1));
|
||||
Assert.NotNull(map);
|
||||
Assert.Equal(new ProgramId(1), map.Value.MainProgramId);
|
||||
Assert.Equal(new ProgramId(1), map.Value.ProgramId);
|
||||
Assert.Equal(0, map.Value.ProgramIndex);
|
||||
|
||||
map = manager.Get(new ProgramId(4));
|
||||
Assert.NotNull(map);
|
||||
Assert.Equal(new ProgramId(1), map.Value.MainProgramId);
|
||||
Assert.Equal(new ProgramId(4), map.Value.ProgramId);
|
||||
Assert.Equal(3, map.Value.ProgramIndex);
|
||||
// ReSharper restore PossibleInvalidOperationException
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProgramId_WithIndex_ReturnsProgramIdOfSpecifiedIndex()
|
||||
{
|
||||
const int count = 5;
|
||||
|
||||
ProgramIndexMapInfoManager manager = CreatePopulatedManager(count, x => (x + 1) * 5);
|
||||
|
||||
// Check that the program ID can be retrieved using any program in the set
|
||||
Assert.Equal(new ProgramId(20), manager.GetProgramId(new ProgramId(5), 3));
|
||||
Assert.Equal(new ProgramId(20), manager.GetProgramId(new ProgramId(10), 3));
|
||||
Assert.Equal(new ProgramId(20), manager.GetProgramId(new ProgramId(15), 3));
|
||||
Assert.Equal(new ProgramId(20), manager.GetProgramId(new ProgramId(20), 3));
|
||||
Assert.Equal(new ProgramId(20), manager.GetProgramId(new ProgramId(25), 3));
|
||||
|
||||
// Check that any index can be used
|
||||
Assert.Equal(new ProgramId(5), manager.GetProgramId(new ProgramId(10), 0));
|
||||
Assert.Equal(new ProgramId(10), manager.GetProgramId(new ProgramId(10), 1));
|
||||
Assert.Equal(new ProgramId(15), manager.GetProgramId(new ProgramId(10), 2));
|
||||
Assert.Equal(new ProgramId(20), manager.GetProgramId(new ProgramId(10), 3));
|
||||
Assert.Equal(new ProgramId(25), manager.GetProgramId(new ProgramId(10), 4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProgramId_InputIdDoesNotExist_ReturnsInvalidId()
|
||||
{
|
||||
const int count = 5;
|
||||
|
||||
ProgramIndexMapInfoManager manager = CreatePopulatedManager(count, x => x + 1);
|
||||
|
||||
Assert.Equal(ProgramId.InvalidId, manager.GetProgramId(new ProgramId(0), 3));
|
||||
Assert.Equal(ProgramId.InvalidId, manager.GetProgramId(new ProgramId(666), 3));
|
||||
Assert.Equal(ProgramId.InvalidId, manager.GetProgramId(new ProgramId(777), 3));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProgramId_InputIndexDoesNotExist_ReturnsInvalidId()
|
||||
{
|
||||
const int count = 5;
|
||||
|
||||
ProgramIndexMapInfoManager manager = CreatePopulatedManager(count, x => x + 1);
|
||||
|
||||
Assert.Equal(ProgramId.InvalidId, manager.GetProgramId(new ProgramId(2), 5));
|
||||
Assert.Equal(ProgramId.InvalidId, manager.GetProgramId(new ProgramId(2), 12));
|
||||
Assert.Equal(ProgramId.InvalidId, manager.GetProgramId(new ProgramId(2), 255));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProgramCount_MapIsEmpty_ReturnsZero()
|
||||
{
|
||||
var manager = new ProgramIndexMapInfoManager();
|
||||
|
||||
Assert.Equal(0, manager.GetProgramCount());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProgramCount_MapHasEntries_ReturnsCorrectCount()
|
||||
{
|
||||
ProgramIndexMapInfoManager manager = CreatePopulatedManager(1, x => x + 1);
|
||||
Assert.Equal(1, manager.GetProgramCount());
|
||||
|
||||
manager = CreatePopulatedManager(10, x => x + 1);
|
||||
Assert.Equal(10, manager.GetProgramCount());
|
||||
|
||||
manager = CreatePopulatedManager(255, x => x + 1);
|
||||
Assert.Equal(255, manager.GetProgramCount());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clear_MapHasEntries_CountIsZero()
|
||||
{
|
||||
const int count = 5;
|
||||
ProgramIndexMapInfoManager manager = CreatePopulatedManager(count, x => x + 1);
|
||||
|
||||
manager.Clear();
|
||||
|
||||
Assert.Equal(0, manager.GetProgramCount());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clear_MapHasEntries_CannotGetOldEntry()
|
||||
{
|
||||
const int count = 5;
|
||||
ProgramIndexMapInfoManager manager = CreatePopulatedManager(count, x => x + 1);
|
||||
|
||||
manager.Clear();
|
||||
|
||||
Assert.Null(manager.Get(new ProgramId(2)));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user