mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add AlignmentMatchingFileSystem and update some of the NCA service
This commit is contained in:
parent
c3cc7a69fb
commit
4699825564
8 changed files with 234 additions and 31 deletions
|
@ -934,6 +934,10 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
|
|||
2,5326,,,,UnexpectedInCompressedStorageC,
|
||||
2,5327,,,,UnexpectedInCompressedStorageD,
|
||||
2,5328,,,,UnexpectedInPathA,
|
||||
2,5333,,,,UnexpectedInSaveDataFileSystemCoreImplA,
|
||||
2,5334,,,,UnexpectedInIntegritySaveDataFileSystemA,
|
||||
2,5335,,,,UnexpectedInJournalIntegritySaveDataFileSystemD,
|
||||
2,5336,,,,UnexpectedInAlignmentMatchableFileSystemA,
|
||||
|
||||
2,6000,6499,,,PreconditionViolation,
|
||||
2,6001,6199,,,InvalidArgument,
|
||||
|
@ -1085,11 +1089,14 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
|
|||
2,6460,,,,GameCardLogoDataSizeInvalid,
|
||||
2,6461,,,,AllocatorAlignmentViolation,
|
||||
2,6462,,,,GlobalFileDataCacheAlreadyEnabled,
|
||||
2,6463,,,,MultiCommitHasOverlappingTargets,The provided file system has already been added to the multi-commit manager.
|
||||
2,6464,,,,MultiCommitAlreadyInProgress,A multi-commit was performed while another multi-commit operation was already running.
|
||||
2,6463,,,,MultiCommitFileSystemDuplicated,The provided file system has already been added to the multi-commit manager.
|
||||
2,6464,,,,SaveDataMultiCommitRepeated,A multi-commit was performed while another multi-commit operation was already running.
|
||||
2,6465,,,,UserNotExist,
|
||||
2,6466,,,,DefaultGlobalFileDataCacheEnabled,
|
||||
2,6467,,,,SaveDataRootPathUnavailable,
|
||||
2,6470,,,,RomMountDivisionSizeUnitCountLimit,
|
||||
2,6471,,,,RomMountCountLimit,
|
||||
2,6472,,,,AocMountDivisionSizeUnitCountLimit,
|
||||
|
||||
2,6600,6699,,,NotFound,
|
||||
2,6602,,,,FileNotFound,
|
||||
|
@ -1150,7 +1157,7 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
|
|||
2,7113,,,,InvalidRamDiskSaveDataFileReadOffset,
|
||||
2,7114,,,,InvalidRamDiskSaveDataCoreDataStorageSize,
|
||||
|
||||
2,7121,7139,,,RamDiskDatabaseCorrupted,
|
||||
2,7121,7129,,,RamDiskDatabaseCorrupted,
|
||||
2,7122,,,,InvalidRamDiskAllocationTableBlock,
|
||||
2,7123,,,,InvalidRamDiskKeyValueListElementIndex,
|
||||
2,7124,,,,InvalidRamDiskAllocationTableChainEntry,
|
||||
|
|
|
|
@ -28,7 +28,8 @@ public enum ContentStorageId
|
|||
{
|
||||
System = 0,
|
||||
User = 1,
|
||||
SdCard = 2
|
||||
SdCard = 2,
|
||||
System0 = 3
|
||||
}
|
||||
|
||||
public enum GameCardPartition
|
||||
|
|
|
@ -1699,6 +1699,14 @@ public static class ResultFs
|
|||
public static Result.Base UnexpectedInCompressedStorageD => new Result.Base(ModuleFs, 5327);
|
||||
/// <summary>Error code: 2002-5328; Inner value: 0x29a002</summary>
|
||||
public static Result.Base UnexpectedInPathA => new Result.Base(ModuleFs, 5328);
|
||||
/// <summary>Error code: 2002-5333; Inner value: 0x29aa02</summary>
|
||||
public static Result.Base UnexpectedInSaveDataFileSystemCoreImplA => new Result.Base(ModuleFs, 5333);
|
||||
/// <summary>Error code: 2002-5334; Inner value: 0x29ac02</summary>
|
||||
public static Result.Base UnexpectedInIntegritySaveDataFileSystemA => new Result.Base(ModuleFs, 5334);
|
||||
/// <summary>Error code: 2002-5335; Inner value: 0x29ae02</summary>
|
||||
public static Result.Base UnexpectedInJournalIntegritySaveDataFileSystemD => new Result.Base(ModuleFs, 5335);
|
||||
/// <summary>Error code: 2002-5336; Inner value: 0x29b002</summary>
|
||||
public static Result.Base UnexpectedInAlignmentMatchableFileSystemA => new Result.Base(ModuleFs, 5336);
|
||||
|
||||
/// <summary>Error code: 2002-6000; Range: 6000-6499; Inner value: 0x2ee002</summary>
|
||||
public static Result.Base PreconditionViolation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6000, 6499); }
|
||||
|
@ -1993,15 +2001,21 @@ public static class ResultFs
|
|||
/// <summary>Error code: 2002-6462; Inner value: 0x327c02</summary>
|
||||
public static Result.Base GlobalFileDataCacheAlreadyEnabled => new Result.Base(ModuleFs, 6462);
|
||||
/// <summary>The provided file system has already been added to the multi-commit manager.<br/>Error code: 2002-6463; Inner value: 0x327e02</summary>
|
||||
public static Result.Base MultiCommitHasOverlappingTargets => new Result.Base(ModuleFs, 6463);
|
||||
public static Result.Base MultiCommitFileSystemDuplicated => new Result.Base(ModuleFs, 6463);
|
||||
/// <summary>A multi-commit was performed while another multi-commit operation was already running.<br/>Error code: 2002-6464; Inner value: 0x328002</summary>
|
||||
public static Result.Base MultiCommitAlreadyInProgress => new Result.Base(ModuleFs, 6464);
|
||||
public static Result.Base SaveDataMultiCommitRepeated => new Result.Base(ModuleFs, 6464);
|
||||
/// <summary>Error code: 2002-6465; Inner value: 0x328202</summary>
|
||||
public static Result.Base UserNotExist => new Result.Base(ModuleFs, 6465);
|
||||
/// <summary>Error code: 2002-6466; Inner value: 0x328402</summary>
|
||||
public static Result.Base DefaultGlobalFileDataCacheEnabled => new Result.Base(ModuleFs, 6466);
|
||||
/// <summary>Error code: 2002-6467; Inner value: 0x328602</summary>
|
||||
public static Result.Base SaveDataRootPathUnavailable => new Result.Base(ModuleFs, 6467);
|
||||
/// <summary>Error code: 2002-6470; Inner value: 0x328c02</summary>
|
||||
public static Result.Base RomMountDivisionSizeUnitCountLimit => new Result.Base(ModuleFs, 6470);
|
||||
/// <summary>Error code: 2002-6471; Inner value: 0x328e02</summary>
|
||||
public static Result.Base RomMountCountLimit => new Result.Base(ModuleFs, 6471);
|
||||
/// <summary>Error code: 2002-6472; Inner value: 0x329002</summary>
|
||||
public static Result.Base AocMountDivisionSizeUnitCountLimit => new Result.Base(ModuleFs, 6472);
|
||||
|
||||
/// <summary>Error code: 2002-6600; Range: 6600-6699; Inner value: 0x339002</summary>
|
||||
public static Result.Base NotFound { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6600, 6699); }
|
||||
|
@ -2112,8 +2126,8 @@ public static class ResultFs
|
|||
/// <summary>Error code: 2002-7114; Inner value: 0x379402</summary>
|
||||
public static Result.Base InvalidRamDiskSaveDataCoreDataStorageSize => new Result.Base(ModuleFs, 7114);
|
||||
|
||||
/// <summary>Error code: 2002-7121; Range: 7121-7139; Inner value: 0x37a202</summary>
|
||||
public static Result.Base RamDiskDatabaseCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 7121, 7139); }
|
||||
/// <summary>Error code: 2002-7121; Range: 7121-7129; Inner value: 0x37a202</summary>
|
||||
public static Result.Base RamDiskDatabaseCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 7121, 7129); }
|
||||
/// <summary>Error code: 2002-7122; Inner value: 0x37a402</summary>
|
||||
public static Result.Base InvalidRamDiskAllocationTableBlock => new Result.Base(ModuleFs, 7122);
|
||||
/// <summary>Error code: 2002-7123; Inner value: 0x37a602</summary>
|
||||
|
|
|
@ -120,7 +120,7 @@ internal class MultiCommitManager : IMultiCommitManager
|
|||
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
|
||||
/// <see cref="ResultFs.MultiCommitFileSystemLimit"/>: The maximum number of file systems have been added.
|
||||
/// <see cref="MaxFileSystemCount"/> file systems may be added to a single multi-commit.<br/>
|
||||
/// <see cref="ResultFs.MultiCommitHasOverlappingTargets"/>: The provided file system has already been added.</returns>
|
||||
/// <see cref="ResultFs.MultiCommitFileSystemDuplicated"/>: The provided file system has already been added.</returns>
|
||||
public Result Add(ref SharedRef<IFileSystemSf> fileSystem)
|
||||
{
|
||||
if (_fileSystemCount >= MaxFileSystemCount)
|
||||
|
@ -134,7 +134,7 @@ internal class MultiCommitManager : IMultiCommitManager
|
|||
for (int i = 0; i < _fileSystemCount; i++)
|
||||
{
|
||||
if (ReferenceEquals(fsaFileSystem.Get, _fileSystems[i].Get))
|
||||
return ResultFs.MultiCommitHasOverlappingTargets.Log();
|
||||
return ResultFs.MultiCommitFileSystemDuplicated.Log();
|
||||
}
|
||||
|
||||
_fileSystems[_fileSystemCount].SetByMove(ref fsaFileSystem.Ref);
|
||||
|
|
|
@ -506,13 +506,12 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager
|
|||
ContentStorageId contentStorageId)
|
||||
{
|
||||
StorageLayoutType storageFlag = contentStorageId == ContentStorageId.System ? StorageLayoutType.Bis : StorageLayoutType.All;
|
||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);
|
||||
using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag);
|
||||
|
||||
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
Accessibility accessibility =
|
||||
programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountContentStorage);
|
||||
Accessibility accessibility = programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountContentStorage);
|
||||
|
||||
if (!accessibility.CanRead || !accessibility.CanWrite)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
@ -522,14 +521,10 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager
|
|||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
// Add all the file system wrappers
|
||||
using var typeSetFileSystem =
|
||||
new SharedRef<IFileSystem>(new StorageLayoutTypeSetFileSystem(ref fileSystem.Ref, storageFlag));
|
||||
|
||||
using var asyncFileSystem =
|
||||
new SharedRef<IFileSystem>(new AsynchronousAccessFileSystem(ref typeSetFileSystem.Ref));
|
||||
|
||||
using SharedRef<IFileSystemSf> fileSystemAdapter =
|
||||
FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref, false);
|
||||
using var typeSetFileSystem = new SharedRef<IFileSystem>(new StorageLayoutTypeSetFileSystem(ref fileSystem.Ref, storageFlag));
|
||||
using var alignmentMatchableFileSystem = new SharedRef<IFileSystem>(new AlignmentMatchableFileSystem(ref fileSystem.Ref));
|
||||
using var asyncFileSystem = new SharedRef<IFileSystem>(new AsynchronousAccessFileSystem(ref alignmentMatchableFileSystem.Ref));
|
||||
using SharedRef<IFileSystemSf> fileSystemAdapter = FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref, allowAllOperations: false);
|
||||
|
||||
outFileSystem.SetByMove(ref fileSystemAdapter.Ref);
|
||||
|
||||
|
@ -544,7 +539,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager
|
|||
if (!programInfo.AccessControl.CanCall(OperationType.RegisterExternalKey))
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
return _serviceImpl.RegisterExternalKey(in rightsId, in accessKey);
|
||||
return _serviceImpl.RegisterExternalKey(in rightsId, in accessKey).Ret();
|
||||
}
|
||||
|
||||
public Result UnregisterExternalKey(in RightsId rightsId)
|
||||
|
@ -555,7 +550,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager
|
|||
if (!programInfo.AccessControl.CanCall(OperationType.RegisterExternalKey))
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
return _serviceImpl.UnregisterExternalKey(in rightsId);
|
||||
return _serviceImpl.UnregisterExternalKey(in rightsId).Ret();
|
||||
}
|
||||
|
||||
public Result UnregisterAllExternalKey()
|
||||
|
@ -584,13 +579,13 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager
|
|||
targetProgramId, programInfo.StorageId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return _serviceImpl.RegisterUpdatePartition(targetProgramId, in programPath, contentAttributes);
|
||||
return _serviceImpl.RegisterUpdatePartition(targetProgramId, in programPath, contentAttributes).Ret();
|
||||
}
|
||||
|
||||
public Result OpenRegisteredUpdatePartition(ref SharedRef<IFileSystemSf> outFileSystem)
|
||||
{
|
||||
var storageFlag = StorageLayoutType.All;
|
||||
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);
|
||||
const StorageLayoutType storageFlag = StorageLayoutType.All;
|
||||
using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag);
|
||||
|
||||
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
@ -612,7 +607,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager
|
|||
new SharedRef<IFileSystem>(new AsynchronousAccessFileSystem(ref typeSetFileSystem.Ref));
|
||||
|
||||
using SharedRef<IFileSystemSf> fileSystemAdapter =
|
||||
FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref, false);
|
||||
FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref, allowAllOperations: false);
|
||||
|
||||
outFileSystem.SetByMove(ref fileSystemAdapter.Ref);
|
||||
|
||||
|
@ -632,7 +627,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager
|
|||
if (!programInfo.AccessControl.CanCall(OperationType.SetEncryptionSeed))
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
return _serviceImpl.SetSdCardEncryptionSeed(in encryptionSeed);
|
||||
return _serviceImpl.SetSdCardEncryptionSeed(in encryptionSeed).Ret();
|
||||
}
|
||||
|
||||
public Result OpenHostFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, ref readonly FspPath path)
|
||||
|
@ -652,7 +647,7 @@ internal class NcaFileSystemService : IRomFileSystemAccessFailureManager
|
|||
|
||||
public Result HandleResolubleAccessFailure(out bool wasDeferred, Result nonDeferredResult)
|
||||
{
|
||||
return _serviceImpl.HandleResolubleAccessFailure(out wasDeferred, nonDeferredResult, _processId);
|
||||
return _serviceImpl.HandleResolubleAccessFailure(out wasDeferred, nonDeferredResult, _processId).Ret();
|
||||
}
|
||||
|
||||
Result IRomFileSystemAccessFailureManager.OpenDataStorageCore(ref SharedRef<IStorage> outStorage,
|
||||
|
|
|
@ -260,12 +260,17 @@ public class NcaFileSystemServiceImpl : IDisposable
|
|||
|
||||
public Result RegisterUpdatePartition(ulong programId, ref readonly Path path, ContentAttributes attributes)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return _updatePartitionPath.Set(programId, in path, attributes).Ret();
|
||||
}
|
||||
|
||||
public Result OpenRegisteredUpdatePartition(ref SharedRef<IFileSystem> outFileSystem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using var path = new Path();
|
||||
Result res = _updatePartitionPath.Get(ref path.Ref(), out ContentAttributes contentAttributes, out ulong updaterProgramId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return OpenFileSystem(ref outFileSystem, in path, contentAttributes, FileSystemProxyType.RegisteredUpdate,
|
||||
updaterProgramId, isDirectory: false).Ret();
|
||||
}
|
||||
|
||||
private Result ParseMountName(ref U8Span path, ref SharedRef<IFileSystem> outFileSystem, out MountInfo outMountInfo)
|
||||
|
|
128
src/LibHac/FsSystem/AlignmentMatchableFileSystem.cs
Normal file
128
src/LibHac/FsSystem/AlignmentMatchableFileSystem.cs
Normal file
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.FsSystem;
|
||||
|
||||
public class AlignmentMatchingFile : ForwardingFile
|
||||
{
|
||||
private readonly OpenMode _openMode;
|
||||
|
||||
public AlignmentMatchingFile(ref UniqueRef<IFile> baseFile, OpenMode openMode) : base(ref baseFile)
|
||||
{
|
||||
_openMode = openMode;
|
||||
}
|
||||
|
||||
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
|
||||
{
|
||||
Assert.SdkNotNull(BaseFile);
|
||||
|
||||
Result res = DryWrite(out bool needsAppend, offset, source.Length, in option, _openMode);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (needsAppend)
|
||||
{
|
||||
res = SetSize(offset + source.Length);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
}
|
||||
|
||||
res = GetSize(out long fileSize);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
const int writeOffsetAlignment = 0x4000; // All writes to the base file must start on a multiple of this value
|
||||
const int writeSizeAlignment = 0x200; // All writes to the base file must end on a multiple of this value, or end at the end of the file
|
||||
|
||||
// The offset and size of the head and tail blocks will be aligned to this value.
|
||||
// Must be >= writeSizeAlignment and <= writeOffsetAlignment
|
||||
const int blockAlignment = 0x4000;
|
||||
|
||||
long alignedStartOffset = Alignment.AlignDown(offset, writeOffsetAlignment);
|
||||
long endOffset = offset + source.Length;
|
||||
long alignedEndOffset = Math.Min(Alignment.AlignUp(endOffset, writeSizeAlignment), fileSize);
|
||||
|
||||
if (alignedStartOffset == offset && alignedEndOffset == endOffset)
|
||||
{
|
||||
return BaseFile.Get.Write(offset, source, in option).Ret();
|
||||
}
|
||||
|
||||
if (!_openMode.HasFlag(OpenMode.Read))
|
||||
return ResultFs.UnexpectedInAlignmentMatchableFileSystemA.Log();
|
||||
|
||||
long alignedBufferEndOffset = Math.Min(Alignment.AlignUp(endOffset, blockAlignment), fileSize);
|
||||
int pooledBufferSize = (int)(alignedBufferEndOffset - alignedStartOffset);
|
||||
|
||||
Assert.SdkLessEqual(pooledBufferSize, PooledBuffer.GetAllocatableSizeMax());
|
||||
|
||||
using var pooledBuffer = new PooledBuffer();
|
||||
pooledBuffer.Allocate(pooledBufferSize, pooledBufferSize);
|
||||
Assert.SdkNotNull(pooledBuffer.GetBuffer());
|
||||
|
||||
// Read the head block into the buffer if the start offset isn't aligned
|
||||
if (offset != alignedStartOffset)
|
||||
{
|
||||
long headEndOffset = Math.Min(Alignment.AlignUp(offset, blockAlignment), fileSize);
|
||||
int headSize = (int)(headEndOffset - alignedStartOffset);
|
||||
Span<byte> headBuffer = pooledBuffer.GetBuffer().Slice(0, headSize);
|
||||
|
||||
res = BaseFile.Get.Read(out long readSizeActual, alignedStartOffset, headBuffer, ReadOption.None);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (headSize != readSizeActual)
|
||||
return ResultFs.UnexpectedInAlignmentMatchableFileSystemA.Log();
|
||||
}
|
||||
|
||||
// In the case where the write size is small enough that it's entirely contained in the head block,
|
||||
// we don't need to check if we need to read a tail block
|
||||
bool headBlockCoversEntireBuffer = offset != alignedStartOffset &&
|
||||
alignedBufferEndOffset == Math.Min(Alignment.AlignUp(offset, blockAlignment), fileSize);
|
||||
|
||||
// Read the tail block into the buffer if the end offset isn't aligned
|
||||
if (!headBlockCoversEntireBuffer && endOffset != alignedEndOffset)
|
||||
{
|
||||
long tailStartOffset = Alignment.AlignDown(endOffset, blockAlignment);
|
||||
int tailSize = (int)(alignedBufferEndOffset - tailStartOffset);
|
||||
Span<byte> tailBuffer = pooledBuffer.GetBuffer().Slice((int)(tailStartOffset - alignedStartOffset), tailSize);
|
||||
|
||||
res = BaseFile.Get.Read(out long readSizeActual, tailStartOffset, tailBuffer, ReadOption.None);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (tailSize != readSizeActual)
|
||||
return ResultFs.UnexpectedInAlignmentMatchableFileSystemA.Log();
|
||||
}
|
||||
|
||||
source.CopyTo(pooledBuffer.GetBuffer().Slice((int)(offset - alignedStartOffset)));
|
||||
|
||||
Span<byte> writeBuffer = pooledBuffer.GetBuffer().Slice(0, (int)(alignedEndOffset - alignedStartOffset));
|
||||
res = BaseFile.Get.Write(alignedStartOffset, writeBuffer, in option);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public class AlignmentMatchableFileSystem : ForwardingFileSystem
|
||||
{
|
||||
public AlignmentMatchableFileSystem(ref SharedRef<IFileSystem> baseFileSystem) : base(ref baseFileSystem) { }
|
||||
|
||||
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, ref readonly Path path, OpenMode mode)
|
||||
{
|
||||
using var baseFile = new UniqueRef<IFile>();
|
||||
Result res = BaseFileSystem.Get.OpenFile(ref baseFile.Ref, in path, mode);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (!mode.HasFlag(OpenMode.Read))
|
||||
{
|
||||
using var alignmentMatchingFile = new UniqueRef<IFile>(new AlignmentMatchingFile(ref baseFile.Ref, mode));
|
||||
outFile.Set(ref alignmentMatchingFile.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
outFile.Set(ref baseFile.Ref);
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
53
tests/LibHac.Tests/FsSystem/AlignmentMatchingFileTests.cs
Normal file
53
tests/LibHac.Tests/FsSystem/AlignmentMatchingFileTests.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Tests.Fs;
|
||||
using Xunit;
|
||||
|
||||
namespace LibHac.Tests.FsSystem;
|
||||
|
||||
public class AlignmentMatchingFileTests
|
||||
{
|
||||
[Fact]
|
||||
public void ReadWrite_AccessCorrectnessTestAgainstMemoryStorage()
|
||||
{
|
||||
SetupRandomAccessTest().Run(1000);
|
||||
}
|
||||
|
||||
private StorageTester SetupRandomAccessTest()
|
||||
{
|
||||
byte[] fileBuffer = new byte[0x180000];
|
||||
byte[] referenceBuffer = new byte[0x180000];
|
||||
|
||||
fileBuffer.AsSpan().Fill(0x55);
|
||||
referenceBuffer.AsSpan().Fill(0x55);
|
||||
|
||||
var referenceStorage = new MemoryStorage(referenceBuffer);
|
||||
|
||||
using var baseFile = new UniqueRef<IFile>(new StorageFile(new MemoryStorage(fileBuffer), OpenMode.All));
|
||||
var alignmentFile = new AlignmentMatchingFile(ref baseFile.Ref, OpenMode.All);
|
||||
var alignmentStorage = new FileStorage(alignmentFile);
|
||||
|
||||
var referenceEntry = new StorageTester.Entry(referenceStorage, referenceBuffer);
|
||||
var alignmentEntry = new StorageTester.Entry(alignmentStorage, fileBuffer);
|
||||
|
||||
var testerConfig = new StorageTester.Configuration
|
||||
{
|
||||
Entries = [referenceEntry, alignmentEntry],
|
||||
AccessParams = [
|
||||
new(50, 0x100),
|
||||
new(50, 0x4000),
|
||||
new(50, 0, 0x40000, 0x100, 0x100),
|
||||
new(50, 0, 0x4000, 0x100, 0)
|
||||
],
|
||||
TaskProbs = [50, 50, 1],
|
||||
AccessTypeProbs = [10, 10, 5],
|
||||
RngSeed = 64972,
|
||||
FrequentAccessBlockCount = 3
|
||||
};
|
||||
|
||||
return new StorageTester(testerConfig);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue