mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Merge pull request #127 from Thealexbarney/fs-shims
Add BIS and more BCAT FS client shims - MountBis - SetBisRootForHost - OpenBisPartition - MountBcatSaveData
This commit is contained in:
commit
1b1e8e6780
11 changed files with 461 additions and 15 deletions
|
@ -12,8 +12,9 @@ namespace LibHac.Common
|
|||
private int _length;
|
||||
|
||||
public bool Overflowed { get; private set; }
|
||||
public int Length => _length;
|
||||
public int Capacity => _buffer.Length - NullTerminatorLength;
|
||||
public readonly int Length => _length;
|
||||
public readonly int Capacity => _buffer.Length - NullTerminatorLength;
|
||||
public readonly Span<byte> Buffer => _buffer;
|
||||
|
||||
public U8StringBuilder(Span<byte> buffer)
|
||||
{
|
||||
|
@ -62,12 +63,12 @@ namespace LibHac.Common
|
|||
return this;
|
||||
}
|
||||
|
||||
private bool HasCapacity(int requiredCapacity)
|
||||
private readonly bool HasCapacity(int requiredCapacity)
|
||||
{
|
||||
return requiredCapacity <= Capacity;
|
||||
}
|
||||
|
||||
private bool HasAdditionalCapacity(int requiredAdditionalCapacity)
|
||||
private readonly bool HasAdditionalCapacity(int requiredAdditionalCapacity)
|
||||
{
|
||||
return HasCapacity(_length + requiredAdditionalCapacity);
|
||||
}
|
||||
|
@ -77,11 +78,11 @@ namespace LibHac.Common
|
|||
_buffer[_length] = 0;
|
||||
}
|
||||
|
||||
private void ThrowIfBufferLengthIsZero()
|
||||
private readonly void ThrowIfBufferLengthIsZero()
|
||||
{
|
||||
if (_buffer.Length == 0) throw new ArgumentException("Buffer length must be greater than 0.");
|
||||
}
|
||||
|
||||
public override string ToString() => StringUtils.Utf8ZToString(_buffer);
|
||||
public override readonly string ToString() => StringUtils.Utf8ZToString(_buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace LibHac.Fs
|
|||
{
|
||||
public class FileStorage2 : StorageBase
|
||||
{
|
||||
protected const long InvalidSize = -1;
|
||||
protected const long SizeNotInitialized = -1;
|
||||
|
||||
private IFile BaseFile { get; set; }
|
||||
protected long FileSize { get; set; }
|
||||
|
@ -14,7 +14,7 @@ namespace LibHac.Fs
|
|||
public FileStorage2(IFile baseFile)
|
||||
{
|
||||
BaseFile = baseFile;
|
||||
FileSize = InvalidSize;
|
||||
FileSize = SizeNotInitialized;
|
||||
}
|
||||
|
||||
protected FileStorage2() { }
|
||||
|
@ -29,7 +29,7 @@ namespace LibHac.Fs
|
|||
|
||||
private Result UpdateSize()
|
||||
{
|
||||
if (FileSize != InvalidSize)
|
||||
if (FileSize != SizeNotInitialized)
|
||||
return Result.Success;
|
||||
|
||||
Result rc = BaseFile.GetSize(out long fileSize);
|
||||
|
@ -87,7 +87,7 @@ namespace LibHac.Fs
|
|||
|
||||
protected override Result SetSizeImpl(long size)
|
||||
{
|
||||
FileSize = InvalidSize;
|
||||
FileSize = SizeNotInitialized;
|
||||
return BaseFile.SetSize(size);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace LibHac.Fs
|
|||
|
||||
private FileStorageBasedFileSystem()
|
||||
{
|
||||
FileSize = InvalidSize;
|
||||
FileSize = SizeNotInitialized;
|
||||
}
|
||||
|
||||
public static Result CreateNew(out FileStorageBasedFileSystem created, IFileSystem baseFileSystem, U8Span path,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using static LibHac.Fs.PathTool;
|
||||
|
@ -77,5 +78,33 @@ namespace LibHac.Fs
|
|||
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
|
||||
public static void Replace(Span<byte> buffer, byte oldChar, byte newChar)
|
||||
{
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
if (buffer[i] == oldChar)
|
||||
{
|
||||
buffer[i] = newChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the extra functions that nn::fs::FspPathPrintf does on the string buffer.
|
||||
/// </summary>
|
||||
/// <param name="builder">The string builder to process.</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public static Result ToSfPath(in this U8StringBuilder builder)
|
||||
{
|
||||
if (builder.Overflowed)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
Replace(builder.Buffer.Slice(builder.Capacity),
|
||||
StringTraits.AltDirectorySeparator,
|
||||
StringTraits.DirectorySeparator);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
56
src/LibHac/Fs/Shim/BcatSaveData.cs
Normal file
56
src/LibHac/Fs/Shim/BcatSaveData.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsService;
|
||||
using LibHac.Ncm;
|
||||
|
||||
namespace LibHac.Fs.Shim
|
||||
{
|
||||
public static class BcatSaveData
|
||||
{
|
||||
public static Result MountBcatSaveData(this FileSystemClient fs, U8Span mountName, TitleId applicationId)
|
||||
{
|
||||
Result rc;
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountBcatSaveDataImpl(fs, mountName, applicationId);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
string logMessage = $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}\"";
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, logMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = MountBcatSaveDataImpl(fs, mountName, applicationId);
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
fs.EnableFileSystemAccessorAccessLog(mountName);
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private static Result MountBcatSaveDataImpl(FileSystemClient fs, U8Span mountName, TitleId applicationId)
|
||||
{
|
||||
Result rc = MountHelpers.CheckMountName(mountName);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
SaveDataAttribute attribute = default;
|
||||
attribute.TitleId = applicationId;
|
||||
attribute.Type = SaveDataType.Bcat;
|
||||
|
||||
rc = fsProxy.OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId.User, ref attribute);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return fs.Register(mountName, fileSystem);
|
||||
}
|
||||
}
|
||||
}
|
178
src/LibHac/Fs/Shim/Bis.cs
Normal file
178
src/LibHac/Fs/Shim/Bis.cs
Normal file
|
@ -0,0 +1,178 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsService;
|
||||
using LibHac.FsSystem;
|
||||
using static LibHac.Fs.CommonMountNames;
|
||||
|
||||
namespace LibHac.Fs.Shim
|
||||
{
|
||||
public static class Bis
|
||||
{
|
||||
private class BisCommonMountNameGenerator : ICommonMountNameGenerator
|
||||
{
|
||||
private BisPartitionId PartitionId { get; }
|
||||
|
||||
public BisCommonMountNameGenerator(BisPartitionId partitionId)
|
||||
{
|
||||
PartitionId = partitionId;
|
||||
}
|
||||
|
||||
public Result GenerateCommonMountName(Span<byte> nameBuffer)
|
||||
{
|
||||
U8Span mountName = GetBisMountName(PartitionId);
|
||||
|
||||
// Add 2 for the mount name separator and null terminator
|
||||
// ReSharper disable once RedundantAssignment
|
||||
int requiredNameBufferSize = StringUtils.GetLength(mountName, PathTools.MountNameLengthMax) + 2;
|
||||
|
||||
Debug.Assert(nameBuffer.Length >= requiredNameBufferSize);
|
||||
|
||||
// ReSharper disable once RedundantAssignment
|
||||
int size = new U8StringBuilder(nameBuffer).Append(mountName).Append(StringTraits.DriveSeparator).Length;
|
||||
Debug.Assert(size == requiredNameBufferSize - 1);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public static Result MountBis(this FileSystemClient fs, U8Span mountName, BisPartitionId partitionId)
|
||||
{
|
||||
return MountBis(fs, mountName, partitionId, default);
|
||||
}
|
||||
|
||||
public static Result MountBis(this FileSystemClient fs, BisPartitionId partitionId, U8Span rootPath)
|
||||
{
|
||||
return MountBis(fs, GetBisMountName(partitionId), partitionId, rootPath);
|
||||
}
|
||||
|
||||
// nn::fs::detail::MountBis
|
||||
private static Result MountBis(FileSystemClient fs, U8Span mountName, BisPartitionId partitionId, U8Span rootPath)
|
||||
{
|
||||
Result rc;
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountBisImpl(fs, mountName, partitionId, rootPath);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
string logMessage = $", name: \"{mountName.ToString()}\", bispartitionid: {partitionId}, path: \"{rootPath.ToString()}\"";
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, logMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = MountBisImpl(fs, mountName, partitionId, rootPath);
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
fs.EnableFileSystemAccessorAccessLog(mountName);
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedParameter.Local
|
||||
private static Result MountBisImpl(FileSystemClient fs, U8Span mountName, BisPartitionId partitionId, U8Span rootPath)
|
||||
{
|
||||
Result rc = MountHelpers.CheckMountNameAcceptingReservedMountName(mountName);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
FsPath sfPath;
|
||||
unsafe { _ = &sfPath; } // workaround for CS0165
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
// Nintendo doesn't use the provided rootPath
|
||||
sfPath.Str[0] = 0;
|
||||
|
||||
rc = fsProxy.OpenBisFileSystem(out IFileSystem fileSystem, ref sfPath, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var nameGenerator = new BisCommonMountNameGenerator(partitionId);
|
||||
|
||||
return fs.Register(mountName, fileSystem, nameGenerator);
|
||||
}
|
||||
|
||||
public static U8Span GetBisMountName(BisPartitionId partitionId)
|
||||
{
|
||||
switch (partitionId)
|
||||
{
|
||||
case BisPartitionId.BootPartition1Root:
|
||||
case BisPartitionId.BootPartition2Root:
|
||||
case BisPartitionId.UserDataRoot:
|
||||
case BisPartitionId.BootConfigAndPackage2Part1:
|
||||
case BisPartitionId.BootConfigAndPackage2Part2:
|
||||
case BisPartitionId.BootConfigAndPackage2Part3:
|
||||
case BisPartitionId.BootConfigAndPackage2Part4:
|
||||
case BisPartitionId.BootConfigAndPackage2Part5:
|
||||
case BisPartitionId.BootConfigAndPackage2Part6:
|
||||
case BisPartitionId.CalibrationBinary:
|
||||
throw new HorizonResultException(default, "The partition specified is not mountable.");
|
||||
|
||||
case BisPartitionId.CalibrationFile:
|
||||
return BisCalibrationFilePartitionMountName;
|
||||
case BisPartitionId.SafeMode:
|
||||
return BisSafeModePartitionMountName;
|
||||
case BisPartitionId.User:
|
||||
return BisUserPartitionMountName;
|
||||
case BisPartitionId.System:
|
||||
return BisSystemPartitionMountName;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(partitionId), partitionId, null);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: Decide how to handle SetBisRootForHost since it allows mounting any directory on the user's computer
|
||||
public static Result SetBisRootForHost(this FileSystemClient fs, BisPartitionId partitionId, U8Span rootPath)
|
||||
{
|
||||
FsPath sfPath;
|
||||
unsafe { _ = &sfPath; } // workaround for CS0165
|
||||
|
||||
int pathLen = StringUtils.GetLength(rootPath, PathTools.MaxPathLength + 1);
|
||||
if (pathLen > PathTools.MaxPathLength)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
if (pathLen > 0)
|
||||
{
|
||||
byte endingSeparator = PathTool.IsSeparator(rootPath[pathLen - 1])
|
||||
? StringTraits.NullTerminator
|
||||
: StringTraits.DirectorySeparator;
|
||||
|
||||
Result rc = new U8StringBuilder(sfPath.Str).Append(rootPath).Append(endingSeparator).ToSfPath();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
sfPath.Str[0] = StringTraits.NullTerminator;
|
||||
}
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
return fsProxy.SetBisRootForHost(partitionId, ref sfPath);
|
||||
}
|
||||
|
||||
public static Result OpenBisPartition(this FileSystemClient fs, out IStorage partitionStorage, BisPartitionId partitionId)
|
||||
{
|
||||
partitionStorage = default;
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
Result rc = fsProxy.OpenBisStorage(out IStorage storage, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
partitionStorage = storage;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result InvalidateBisCache(this FileSystemClient fs)
|
||||
{
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
return fsProxy.InvalidateBisCache();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@ namespace LibHac.Tests.Fs.FileSystemClientTests
|
|||
{
|
||||
public static class FileSystemServerFactory
|
||||
{
|
||||
public static FileSystemServer CreateServer(bool sdCardInserted)
|
||||
public static FileSystemServer CreateServer(bool sdCardInserted, out IFileSystem rootFs)
|
||||
{
|
||||
var rootFs = new InMemoryFileSystem();
|
||||
rootFs = new InMemoryFileSystem();
|
||||
|
||||
var defaultObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(rootFs, new Keyset());
|
||||
|
||||
|
@ -25,7 +25,14 @@ namespace LibHac.Tests.Fs.FileSystemClientTests
|
|||
|
||||
public static FileSystemClient CreateClient(bool sdCardInserted)
|
||||
{
|
||||
FileSystemServer fsServer = CreateServer(sdCardInserted);
|
||||
FileSystemServer fsServer = CreateServer(sdCardInserted, out _);
|
||||
|
||||
return fsServer.CreateFileSystemClient();
|
||||
}
|
||||
|
||||
public static FileSystemClient CreateClient(out IFileSystem rootFs)
|
||||
{
|
||||
FileSystemServer fsServer = CreateServer(false, out rootFs);
|
||||
|
||||
return fsServer.CreateFileSystemClient();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.Ncm;
|
||||
using Xunit;
|
||||
|
||||
namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
|
||||
{
|
||||
public class BcatSaveData
|
||||
{
|
||||
[Fact]
|
||||
public void MountBcatSaveData_SaveDoesNotExist_ReturnsTargetNotFound()
|
||||
{
|
||||
var applicationId = new TitleId(1);
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(true);
|
||||
|
||||
Assert.Result(ResultFs.TargetNotFound, fs.MountBcatSaveData("bcat_test".ToU8Span(), applicationId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MountBcatSaveData_SaveExists_ReturnsSuccess()
|
||||
{
|
||||
var applicationId = new TitleId(1);
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(true);
|
||||
|
||||
Assert.Success(fs.CreateBcatSaveData(applicationId, 0x400000));
|
||||
Assert.Success(fs.MountBcatSaveData("bcat_test".ToU8Span(), applicationId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MountBcatSaveData_WrittenDataPersists()
|
||||
{
|
||||
var applicationId = new TitleId(1);
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(true);
|
||||
|
||||
Assert.Success(fs.CreateBcatSaveData(applicationId, 0x400000));
|
||||
Assert.Success(fs.MountBcatSaveData("bcat_test".ToU8Span(), applicationId));
|
||||
|
||||
// Check that the path doesn't exist
|
||||
Assert.Result(ResultFs.PathNotFound, fs.GetEntryType(out _, "bcat_test:/file".ToU8Span()));
|
||||
|
||||
fs.CreateFile("bcat_test:/file".ToU8Span(), 0);
|
||||
fs.Commit("bcat_test".ToU8Span());
|
||||
fs.Unmount("bcat_test".ToU8Span());
|
||||
|
||||
Assert.Success(fs.MountBcatSaveData("bcat_test".ToU8Span(), applicationId));
|
||||
Assert.Success(fs.GetEntryType(out DirectoryEntryType type, "bcat_test:/file".ToU8Span()));
|
||||
Assert.Equal(DirectoryEntryType.File, type);
|
||||
}
|
||||
}
|
||||
}
|
95
tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/Bis.cs
Normal file
95
tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/Bis.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
using Xunit;
|
||||
|
||||
namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
|
||||
{
|
||||
public class Bis
|
||||
{
|
||||
[Fact]
|
||||
public void MountBis_MountCalibrationPartition_OpensCorrectDirectory()
|
||||
{
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(out IFileSystem rootFs);
|
||||
|
||||
Assert.Success(fs.MountBis("calib".ToU8Span(), BisPartitionId.CalibrationFile));
|
||||
|
||||
// Create a file in the opened file system
|
||||
Assert.Success(fs.CreateFile("calib:/file".ToU8Span(), 0));
|
||||
|
||||
// Make sure the file exists on the root file system
|
||||
Assert.Success(rootFs.GetEntryType(out DirectoryEntryType type, "/bis/cal/file".ToU8Span()));
|
||||
Assert.Equal(DirectoryEntryType.File, type);
|
||||
}
|
||||
[Fact]
|
||||
public void MountBis_MountSafePartition_OpensCorrectDirectory()
|
||||
{
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(out IFileSystem rootFs);
|
||||
|
||||
Assert.Success(fs.MountBis("safe".ToU8Span(), BisPartitionId.SafeMode));
|
||||
|
||||
// Create a file in the opened file system
|
||||
Assert.Success(fs.CreateFile("safe:/file".ToU8Span(), 0));
|
||||
|
||||
// Make sure the file exists on the root file system
|
||||
Assert.Success(rootFs.GetEntryType(out DirectoryEntryType type, "/bis/safe/file".ToU8Span()));
|
||||
Assert.Equal(DirectoryEntryType.File, type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MountBis_MountSystemPartition_OpensCorrectDirectory()
|
||||
{
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(out IFileSystem rootFs);
|
||||
|
||||
Assert.Success(fs.MountBis("system".ToU8Span(), BisPartitionId.System));
|
||||
|
||||
// Create a file in the opened file system
|
||||
Assert.Success(fs.CreateFile("system:/file".ToU8Span(), 0));
|
||||
|
||||
// Make sure the file exists on the root file system
|
||||
Assert.Success(rootFs.GetEntryType(out DirectoryEntryType type, "/bis/system/file".ToU8Span()));
|
||||
Assert.Equal(DirectoryEntryType.File, type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MountBis_MountUserPartition_OpensCorrectDirectory()
|
||||
{
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(out IFileSystem rootFs);
|
||||
|
||||
Assert.Success(fs.MountBis("user".ToU8Span(), BisPartitionId.User));
|
||||
|
||||
// Create a file in the opened file system
|
||||
Assert.Success(fs.CreateFile("user:/file".ToU8Span(), 0));
|
||||
|
||||
// Make sure the file exists on the root file system
|
||||
Assert.Success(rootFs.GetEntryType(out DirectoryEntryType type, "/bis/user/file".ToU8Span()));
|
||||
Assert.Equal(DirectoryEntryType.File, type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MountBis_WithRootPath_IgnoresRootPath()
|
||||
{
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(out IFileSystem rootFs);
|
||||
|
||||
Assert.Success(fs.MountBis(BisPartitionId.User, "/sub".ToU8Span()));
|
||||
|
||||
// Create a file in the opened file system
|
||||
Assert.Success(fs.CreateFile("@User:/file".ToU8Span(), 0));
|
||||
|
||||
// Make sure the file wasn't created in the sub path
|
||||
Assert.Result(ResultFs.PathNotFound, rootFs.GetEntryType(out _, "/bis/user/sub/file".ToU8Span()));
|
||||
|
||||
// Make sure the file was created in the main path
|
||||
Assert.Success(rootFs.GetEntryType(out DirectoryEntryType type, "/bis/user/file".ToU8Span()));
|
||||
Assert.Equal(DirectoryEntryType.File, type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MountBis_InvalidPartition_ReturnsInvalidArgument()
|
||||
{
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(out IFileSystem rootFs);
|
||||
|
||||
Assert.Result(ResultFs.InvalidArgument, fs.MountBis("boot1".ToU8Span(), BisPartitionId.BootPartition1Root));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
|
|||
Assert.Success(fs.GetEntryType(out DirectoryEntryType type, "cache:/file".ToU8Span()));
|
||||
Assert.Equal(DirectoryEntryType.File, type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MountCacheStorage_SdCardIsPreferredOverBis()
|
||||
{
|
||||
|
|
|
@ -84,5 +84,33 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
|
|||
|
||||
Assert.Equal(expectedIndexes, actualIndexes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateBcatSaveData_DoesNotExist_SaveIsCreated()
|
||||
{
|
||||
var applicationId = new TitleId(1);
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(true);
|
||||
|
||||
Assert.Success(fs.CreateBcatSaveData(applicationId, 0x400000));
|
||||
|
||||
fs.OpenSaveDataIterator(out SaveDataIterator iterator, SaveDataSpaceId.User);
|
||||
|
||||
var info = new SaveDataInfo[2];
|
||||
iterator.ReadSaveDataInfo(out long entriesRead, info);
|
||||
|
||||
Assert.Equal(1, entriesRead);
|
||||
Assert.Equal(applicationId, info[0].TitleId);
|
||||
Assert.Equal(SaveDataType.Bcat, info[0].Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateBcatSaveData_AlreadyExists_ReturnsPathAlreadyExists()
|
||||
{
|
||||
var applicationId = new TitleId(1);
|
||||
FileSystemClient fs = FileSystemServerFactory.CreateClient(true);
|
||||
|
||||
Assert.Success(fs.CreateBcatSaveData(applicationId, 0x400000));
|
||||
Assert.Result(ResultFs.PathAlreadyExists, fs.CreateBcatSaveData(applicationId, 0x400000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue