Add FileStorageBasedFileSystem

This commit is contained in:
Alex Barney 2019-11-03 17:03:33 -07:00
parent 3d7ff652e0
commit 31563ad108
7 changed files with 241 additions and 1 deletions

View file

@ -45,6 +45,30 @@ namespace LibHac.Common
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>
/// Concatenates 2 byte strings.
/// </summary>

View 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();
}
}
}
}

View 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);
}
}
}

View file

@ -95,6 +95,18 @@ namespace LibHac.Fs
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);
}
@ -106,6 +118,18 @@ namespace LibHac.Fs
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);
}

View file

@ -122,7 +122,8 @@ namespace LibHac.Fs
Read = 1,
Write = 2,
AllowAppend = 4,
ReadWrite = Read | Write
ReadWrite = Read | Write,
All = Read | Write | AllowAppend
}
[Flags]

View 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;
}
}

View file

@ -109,6 +109,7 @@
public static Result SubStorageNotResizable => new Result(ModuleFs, 6302);
public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6303);
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 UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6316);
public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324);