Add FileHandleStorage and a new SubStorage class

This commit is contained in:
Alex Barney 2019-09-25 17:16:59 -05:00
parent c89bc1c706
commit 955fff8efc
8 changed files with 215 additions and 9 deletions

View file

@ -0,0 +1,98 @@
using System;
namespace LibHac.Fs
{
public class FileHandleStorage : StorageBase
{
private const long InvalidSize = -1;
private readonly object _locker = new object();
private FileSystemManager FsManager { get; }
private FileHandle Handle { get; }
private long FileSize { get; set; } = InvalidSize;
private bool CloseHandle { get; }
public FileHandleStorage(FileHandle handle) : this(handle, false) { }
public FileHandleStorage(FileHandle handle, bool closeHandleOnDispose)
{
Handle = handle;
CloseHandle = closeHandleOnDispose;
FsManager = Handle.File.Parent.FsManager;
}
public override Result Read(long offset, Span<byte> destination)
{
lock (_locker)
{
if (destination.Length == 0) return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
if (destination.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log();
if (!IsRangeValid(offset, destination.Length, FileSize)) return ResultFs.ValueOutOfRange.Log();
return FsManager.ReadFile(Handle, offset, destination);
}
}
public override Result Write(long offset, ReadOnlySpan<byte> source)
{
lock (_locker)
{
if (source.Length == 0) return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
if (source.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log();
if (!IsRangeValid(offset, source.Length, FileSize)) return ResultFs.ValueOutOfRange.Log();
return FsManager.WriteFile(Handle, offset, source);
}
}
public override Result Flush()
{
return FsManager.FlushFile(Handle);
}
public override Result SetSize(long size)
{
FileSize = InvalidSize;
return FsManager.SetFileSize(Handle, size);
}
public override Result GetSize(out long size)
{
size = default;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
size = FileSize;
return Result.Success;
}
private Result UpdateSize()
{
if (FileSize != InvalidSize) return Result.Success;
Result rc = FsManager.GetFileSize(out long fileSize, Handle);
if (rc.IsFailure()) return rc;
FileSize = fileSize;
return Result.Success;
}
public override void Dispose()
{
if (CloseHandle)
{
FsManager.CloseFile(Handle);
}
}
}
}

View file

@ -26,7 +26,7 @@ namespace LibHac.Fs
public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan<byte> source, WriteOption options) public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan<byte> source, WriteOption options)
{ {
return FsManager.WriteFile(handle, source, offset, options); return FsManager.WriteFile(handle, offset, source, options);
} }
public Result FlushFile(FileHandle handle) public Result FlushFile(FileHandle handle)

View file

@ -433,12 +433,12 @@ namespace LibHac.Fs
return rc; return rc;
} }
public Result WriteFile(FileHandle handle, ReadOnlySpan<byte> source, long offset) public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan<byte> source)
{ {
return WriteFile(handle, source, offset, WriteOption.None); return WriteFile(handle, offset, source, WriteOption.None);
} }
public Result WriteFile(FileHandle handle, ReadOnlySpan<byte> source, long offset, WriteOption option) public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan<byte> source, WriteOption option)
{ {
Result rc; Result rc;
@ -607,9 +607,9 @@ namespace LibHac.Fs
mountName = path.Slice(0, mountLen); mountName = path.Slice(0, mountLen);
if (mountLen + 2 < path.Length) if (mountLen + 1 < path.Length)
{ {
subPath = path.Slice(mountLen + 2); subPath = path.Slice(mountLen + 1);
} }
else else
{ {

View file

@ -76,7 +76,7 @@ namespace LibHac.Fs
rc = fs.ReadFile(out long _, sourceHandle, offset, buf); rc = fs.ReadFile(out long _, sourceHandle, offset, buf);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
rc = fs.WriteFile(destHandle, buf, offset); rc = fs.WriteFile(destHandle, offset, buf);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
logger?.ReportAdd(toRead); logger?.ReportAdd(toRead);

View file

@ -0,0 +1,20 @@
using System;
namespace LibHac.Fs
{
public abstract class StorageBase : IStorage
{
public abstract Result Read(long offset, Span<byte> destination);
public abstract Result Write(long offset, ReadOnlySpan<byte> source);
public abstract Result Flush();
public abstract Result SetSize(long size);
public abstract Result GetSize(out long size);
public virtual void Dispose() { }
public static bool IsRangeValid(long offset, long size, long totalSize)
{
return size <= totalSize && offset <= totalSize - size;
}
}
}

View file

@ -0,0 +1,85 @@
using System;
namespace LibHac.Fs
{
public class SubStorage2 : StorageBase
{
private IStorage BaseStorage { get; }
private long Offset { get; }
private long Size { get; set; }
public bool IsResizable { get; set; }
public SubStorage2(IStorage baseStorage, long offset, long size)
{
BaseStorage = baseStorage;
Offset = offset;
Size = size;
}
public SubStorage2(SubStorage2 baseStorage, long offset, long size)
{
BaseStorage = baseStorage.BaseStorage;
Offset = baseStorage.Offset + offset;
Size = size;
}
public override Result Read(long offset, Span<byte> destination)
{
if (BaseStorage == null) return ResultFs.Result6902.Log();
if (destination.Length == 0) return Result.Success;
if (Size < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log();
if (!IsRangeValid(offset, destination.Length, Size)) return ResultFs.ValueOutOfRange.Log();
return BaseStorage.Read(Offset + offset, destination);
}
public override Result Write(long offset, ReadOnlySpan<byte> source)
{
if (BaseStorage == null) return ResultFs.Result6902.Log();
if (source.Length == 0) return Result.Success;
if (Size < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log();
if (!IsRangeValid(offset, source.Length, Size)) return ResultFs.ValueOutOfRange.Log();
return BaseStorage.Write(Offset + offset, source);
}
public override Result Flush()
{
if (BaseStorage == null) return ResultFs.Result6902.Log();
return BaseStorage.Flush();
}
public override Result SetSize(long size)
{
if (BaseStorage == null) return ResultFs.Result6902.Log();
if (!IsResizable) return ResultFs.SubStorageNotResizable.Log();
if (size < 0 || Offset < 0) return ResultFs.ValueOutOfRange.Log();
Result rc = BaseStorage.GetSize(out long baseSize);
if (rc.IsFailure()) return rc;
if (baseSize != Offset + Size)
{
// SubStorage cannot be resized unless it is located at the end of the base storage.
return ResultFs.SubStorageNotResizableMiddleOfFile.Log();
}
rc = BaseStorage.SetSize(Offset + size);
if (rc.IsFailure()) return rc;
Size = size;
return Result.Success;
}
public override Result GetSize(out long size)
{
size = default;
if (BaseStorage == null) return ResultFs.Result6902.Log();
size = Size;
return Result.Success;
}
}
}

View file

@ -63,6 +63,7 @@ namespace LibHac.FsSystem
rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead)); rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead));
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
bytesRead = toRead;
return Result.Success; return Result.Success;
} }

View file

@ -49,11 +49,13 @@ namespace LibHac.FsSystem
public Result CreateFile(string path, long size, CreateFileOptions options, byte[] key) public Result CreateFile(string path, long size, CreateFileOptions options, byte[] key)
{ {
long containerSize = AesXtsFile.HeaderLength + Util.AlignUp(size, 0x10); long containerSize = AesXtsFile.HeaderLength + Util.AlignUp(size, 0x10);
BaseFileSystem.CreateFile(path, containerSize, options);
Result rc = BaseFileSystem.CreateFile(path, containerSize, options);
if (rc.IsFailure()) return rc;
var header = new AesXtsFileHeader(key, size, path, KekSource, ValidationKey); var header = new AesXtsFileHeader(key, size, path, KekSource, ValidationKey);
Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write); rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
using (baseFile) using (baseFile)