mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add FileHandleStorage and a new SubStorage class
This commit is contained in:
parent
c89bc1c706
commit
955fff8efc
8 changed files with 215 additions and 9 deletions
98
src/LibHac/Fs/FileHandleStorage.cs
Normal file
98
src/LibHac/Fs/FileHandleStorage.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ namespace LibHac.Fs
|
|||
|
||||
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)
|
||||
|
|
|
@ -433,12 +433,12 @@ namespace LibHac.Fs
|
|||
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;
|
||||
|
||||
|
@ -607,9 +607,9 @@ namespace LibHac.Fs
|
|||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace LibHac.Fs
|
|||
rc = fs.ReadFile(out long _, sourceHandle, offset, buf);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = fs.WriteFile(destHandle, buf, offset);
|
||||
rc = fs.WriteFile(destHandle, offset, buf);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
logger?.ReportAdd(toRead);
|
||||
|
|
20
src/LibHac/Fs/StorageBase.cs
Normal file
20
src/LibHac/Fs/StorageBase.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
85
src/LibHac/Fs/SubStorage2.cs
Normal file
85
src/LibHac/Fs/SubStorage2.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -63,6 +63,7 @@ namespace LibHac.FsSystem
|
|||
rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
bytesRead = toRead;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,11 +49,13 @@ namespace LibHac.FsSystem
|
|||
public Result CreateFile(string path, long size, CreateFileOptions options, byte[] key)
|
||||
{
|
||||
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);
|
||||
|
||||
Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write);
|
||||
rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using (baseFile)
|
||||
|
|
Loading…
Reference in a new issue