mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add FileStorageBasedFileSystem
This commit is contained in:
parent
3d7ff652e0
commit
31563ad108
7 changed files with 241 additions and 1 deletions
|
@ -45,6 +45,30 @@ namespace LibHac.Common
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int Compare(ReadOnlySpan<byte> s1, ReadOnlySpan<byte> s2)
|
||||||
|
{
|
||||||
|
int maxLen = Math.Min(s1.Length, s2.Length);
|
||||||
|
|
||||||
|
return Compare(s1, s2, maxLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Compare(ReadOnlySpan<byte> s1, ReadOnlySpan<byte> s2, int maxLen)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < maxLen; i++)
|
||||||
|
{
|
||||||
|
byte c1 = s1[i];
|
||||||
|
byte c2 = s2[i];
|
||||||
|
|
||||||
|
if (c1 != c2)
|
||||||
|
return c1 - c2;
|
||||||
|
|
||||||
|
if (c1 == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Concatenates 2 byte strings.
|
/// Concatenates 2 byte strings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
130
src/LibHac/Fs/FileStorage2.cs
Normal file
130
src/LibHac/Fs/FileStorage2.cs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace LibHac.Fs
|
||||||
|
{
|
||||||
|
public class FileStorage2 : StorageBase
|
||||||
|
{
|
||||||
|
private const long InvalidSize = -1;
|
||||||
|
|
||||||
|
private IFile BaseFile { get; set; }
|
||||||
|
private long FileSize { get; set; }
|
||||||
|
|
||||||
|
public FileStorage2(IFile baseFile)
|
||||||
|
{
|
||||||
|
BaseFile = baseFile;
|
||||||
|
FileSize = InvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FileStorage2() { }
|
||||||
|
|
||||||
|
protected void SetFile(IFile file)
|
||||||
|
{
|
||||||
|
Debug.Assert(file != null);
|
||||||
|
Debug.Assert(BaseFile == null);
|
||||||
|
|
||||||
|
BaseFile = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result UpdateSize()
|
||||||
|
{
|
||||||
|
if (FileSize != InvalidSize)
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
Result rc = BaseFile.GetSize(out long fileSize);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
FileSize = fileSize;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result ReadImpl(long offset, Span<byte> destination)
|
||||||
|
{
|
||||||
|
if (destination.Length == 0)
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
Result rc = UpdateSize();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, destination.Length, FileSize))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
|
return BaseFile.Read(out _, offset, destination, ReadOption.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
|
||||||
|
{
|
||||||
|
if (source.Length == 0)
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
Result rc = UpdateSize();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
if (!IsRangeValid(offset, source.Length, FileSize))
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
|
||||||
|
return BaseFile.Write(offset, source, WriteOption.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result FlushImpl()
|
||||||
|
{
|
||||||
|
return BaseFile.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result GetSizeImpl(out long size)
|
||||||
|
{
|
||||||
|
Result rc = UpdateSize();
|
||||||
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
size = default;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = FileSize;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result SetSizeImpl(long size)
|
||||||
|
{
|
||||||
|
FileSize = InvalidSize;
|
||||||
|
return BaseFile.SetSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Result OperateRangeImpl(Span<byte> outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan<byte> inBuffer)
|
||||||
|
{
|
||||||
|
switch (operationId)
|
||||||
|
{
|
||||||
|
case OperationId.InvalidateCache:
|
||||||
|
case OperationId.QueryRange:
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
if (operationId == OperationId.QueryRange)
|
||||||
|
{
|
||||||
|
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
|
||||||
|
{
|
||||||
|
return ResultFs.InvalidSize.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
Unsafe.As<byte, QueryRangeInfo>(ref outBuffer[0]) = new QueryRangeInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result rc = UpdateSize();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
if (size < 0 || offset < 0)
|
||||||
|
{
|
||||||
|
return ResultFs.ValueOutOfRange.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
return BaseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.UnsupportedOperationInFileStorageOperateRange.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
src/LibHac/Fs/FileStorageBasedFileSystem.cs
Normal file
49
src/LibHac/Fs/FileStorageBasedFileSystem.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
namespace LibHac.Fs
|
||||||
|
{
|
||||||
|
public class FileStorageBasedFileSystem : FileStorage2
|
||||||
|
{
|
||||||
|
private IFileSystem BaseFileSystem { get; set; }
|
||||||
|
private IFile BaseFile { get; set; }
|
||||||
|
|
||||||
|
private FileStorageBasedFileSystem() : base() { }
|
||||||
|
|
||||||
|
public static Result CreateNew(out FileStorageBasedFileSystem created, IFileSystem baseFileSystem, string path,
|
||||||
|
OpenMode mode)
|
||||||
|
{
|
||||||
|
var obj = new FileStorageBasedFileSystem();
|
||||||
|
Result rc = obj.Initialize(baseFileSystem, path, mode);
|
||||||
|
|
||||||
|
if (rc.IsSuccess())
|
||||||
|
{
|
||||||
|
created = obj;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Dispose();
|
||||||
|
created = default;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result Initialize(IFileSystem baseFileSystem, string path, OpenMode mode)
|
||||||
|
{
|
||||||
|
Result rc = baseFileSystem.OpenFile(out IFile file, path, mode);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
SetFile(file);
|
||||||
|
BaseFile = file;
|
||||||
|
BaseFileSystem = baseFileSystem;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
BaseFile?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,6 +95,18 @@ namespace LibHac.Fs
|
||||||
return ResultFs.PreconditionViolation.Log();
|
return ResultFs.PreconditionViolation.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (path == null)
|
||||||
|
{
|
||||||
|
directory = default;
|
||||||
|
return ResultFs.NullArgument.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mode & ~OpenDirectoryMode.All) != 0 || (mode & OpenDirectoryMode.All) == 0)
|
||||||
|
{
|
||||||
|
directory = default;
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
|
||||||
return OpenDirectoryImpl(out directory, path, mode);
|
return OpenDirectoryImpl(out directory, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +118,18 @@ namespace LibHac.Fs
|
||||||
return ResultFs.PreconditionViolation.Log();
|
return ResultFs.PreconditionViolation.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (path == null)
|
||||||
|
{
|
||||||
|
file = default;
|
||||||
|
return ResultFs.NullArgument.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mode & ~OpenMode.All) != 0 || (mode & OpenMode.ReadWrite) == 0)
|
||||||
|
{
|
||||||
|
file = default;
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
|
||||||
return OpenFileImpl(out file, path, mode);
|
return OpenFileImpl(out file, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,8 @@ namespace LibHac.Fs
|
||||||
Read = 1,
|
Read = 1,
|
||||||
Write = 2,
|
Write = 2,
|
||||||
AllowAppend = 4,
|
AllowAppend = 4,
|
||||||
ReadWrite = Read | Write
|
ReadWrite = Read | Write,
|
||||||
|
All = Read | Write | AllowAppend
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
|
11
src/LibHac/Fs/QueryRangeInfo.cs
Normal file
11
src/LibHac/Fs/QueryRangeInfo.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace LibHac.Fs
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 0x40)]
|
||||||
|
public struct QueryRangeInfo
|
||||||
|
{
|
||||||
|
public uint AesCtrKeyType;
|
||||||
|
public uint SpeedEmulationType;
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,6 +109,7 @@
|
||||||
public static Result SubStorageNotResizable => new Result(ModuleFs, 6302);
|
public static Result SubStorageNotResizable => new Result(ModuleFs, 6302);
|
||||||
public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6303);
|
public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6303);
|
||||||
public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6304);
|
public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6304);
|
||||||
|
public static Result UnsupportedOperationInFileStorageOperateRange => new Result(ModuleFs, 6306);
|
||||||
public static Result UnsupportedOperationInAesCtrExStorageWrite => new Result(ModuleFs, 6310);
|
public static Result UnsupportedOperationInAesCtrExStorageWrite => new Result(ModuleFs, 6310);
|
||||||
public static Result UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6316);
|
public static Result UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6316);
|
||||||
public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324);
|
public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324);
|
||||||
|
|
Loading…
Reference in a new issue