mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Update SubdirectoryFileSystem and InMemoryFileSystem
This commit is contained in:
parent
4efe313281
commit
b86b57a4d3
@ -29,6 +29,76 @@ namespace LibHac.Fs
|
||||
[DebuggerDisplay("{" + nameof(ToString) + "(),nq}")]
|
||||
public ref struct Path
|
||||
{
|
||||
[DebuggerDisplay("{" + nameof(ToString) + "(),nq}")]
|
||||
public struct Stored : IDisposable
|
||||
{
|
||||
private byte[] _buffer;
|
||||
private int _length;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
byte[] buffer = Shared.Move(ref _buffer);
|
||||
if (buffer is not null)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public Result Initialize(in Path path)
|
||||
{
|
||||
if (!path._isNormalized)
|
||||
return ResultFs.NotNormalized.Log();
|
||||
|
||||
_length = path.GetLength();
|
||||
|
||||
Result rc = Preallocate(_length + NullTerminatorLength);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
int bytesCopied = StringUtils.Copy(_buffer, path._string, _length + NullTerminatorLength);
|
||||
|
||||
if (bytesCopied != _length)
|
||||
return ResultFs.UnexpectedInPathA.Log();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public readonly int GetLength() => _length;
|
||||
public readonly ReadOnlySpan<byte> GetString() => _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="Path"/> from this <see cref="Path.Stored"/>. This <see cref="Stored"/>
|
||||
/// must not be reinitialized or disposed for the lifetime of the created <see cref="Path"/>.
|
||||
/// </summary>
|
||||
/// <returns>The created <see cref="Path"/>.</returns>
|
||||
public readonly Path GetPath()
|
||||
{
|
||||
return new Path
|
||||
{
|
||||
_string = _buffer,
|
||||
_isNormalized = true
|
||||
};
|
||||
}
|
||||
|
||||
private Result Preallocate(int length)
|
||||
{
|
||||
if (_buffer is not null && _buffer.Length > length)
|
||||
return Result.Success;
|
||||
|
||||
int alignedLength = Alignment.AlignUpPow2(length, WriteBufferAlignmentLength);
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(alignedLength);
|
||||
|
||||
byte[] oldBuffer = _buffer;
|
||||
_buffer = buffer;
|
||||
|
||||
if (oldBuffer is not null)
|
||||
ArrayPool<byte>.Shared.Return(oldBuffer);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public override string ToString() => StringUtils.Utf8ZToString(_buffer);
|
||||
}
|
||||
|
||||
private const int SeparatorLength = 1;
|
||||
private const int NullTerminatorLength = 1;
|
||||
private const int WriteBufferAlignmentLength = 8;
|
||||
@ -49,7 +119,7 @@ namespace LibHac.Fs
|
||||
}
|
||||
}
|
||||
|
||||
private Span<byte> GetWriteBuffer()
|
||||
internal Span<byte> GetWriteBuffer()
|
||||
{
|
||||
Assert.SdkRequires(_writeBuffer is not null);
|
||||
return _writeBuffer.AsSpan();
|
||||
@ -191,6 +261,22 @@ namespace LibHac.Fs
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Initialize(in Stored other)
|
||||
{
|
||||
int otherLength = other.GetLength();
|
||||
|
||||
Result rc = Preallocate(otherLength + NullTerminatorLength);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
int bytesCopied = StringUtils.Copy(_writeBuffer, other.GetString(), otherLength + NullTerminatorLength);
|
||||
|
||||
if (bytesCopied != otherLength)
|
||||
return ResultFs.UnexpectedInPathA.Log();
|
||||
|
||||
_isNormalized = true;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result InitializeImpl(ReadOnlySpan<byte> path, int length)
|
||||
{
|
||||
if (length == 0 || path.At(0) == NullTerminator)
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
@ -23,23 +22,15 @@ namespace LibHac.Fs
|
||||
|
||||
protected override Result DoCreateDirectory(in Path path)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return FsTable.AddDirectory(normalizedPath);
|
||||
return FsTable.AddDirectory(new U8Span(path.GetString()));
|
||||
}
|
||||
|
||||
protected override Result DoCreateDirectory(U8Span path, NxFileAttributes archiveAttribute)
|
||||
protected override Result DoCreateDirectory(in Path path, NxFileAttributes archiveAttribute)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
Result rc = FsTable.AddDirectory(new U8Span(path.GetString()));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = FsTable.AddDirectory(normalizedPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = FsTable.GetDirectory(normalizedPath, out DirectoryNode dir);
|
||||
rc = FsTable.GetDirectory(new U8Span(path.GetString()), out DirectoryNode dir);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
dir.Attributes = archiveAttribute;
|
||||
@ -48,14 +39,10 @@ namespace LibHac.Fs
|
||||
|
||||
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
Result rc = FsTable.AddFile(new U8Span(path.GetString()));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = FsTable.AddFile(normalizedPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = FsTable.GetFile(normalizedPath, out FileNode file);
|
||||
rc = FsTable.GetFile(new U8Span(path.GetString()), out FileNode file);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return file.File.SetSize(size);
|
||||
@ -63,49 +50,29 @@ namespace LibHac.Fs
|
||||
|
||||
protected override Result DoDeleteDirectory(in Path path)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return FsTable.DeleteDirectory(normalizedPath, false);
|
||||
return FsTable.DeleteDirectory(new U8Span(path.GetString()), false);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectoryRecursively(in Path path)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return FsTable.DeleteDirectory(normalizedPath, true);
|
||||
return FsTable.DeleteDirectory(new U8Span(path.GetString()), true);
|
||||
}
|
||||
|
||||
protected override Result DoCleanDirectoryRecursively(in Path path)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return FsTable.CleanDirectory(normalizedPath);
|
||||
return FsTable.CleanDirectory(new U8Span(path.GetString()));
|
||||
}
|
||||
|
||||
protected override Result DoDeleteFile(in Path path)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return FsTable.DeleteFile(normalizedPath);
|
||||
return FsTable.DeleteFile(new U8Span(path.GetString()));
|
||||
}
|
||||
|
||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out directory);
|
||||
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = FsTable.GetDirectory(normalizedPath, out DirectoryNode dirNode);
|
||||
Result rc = FsTable.GetDirectory(new U8Span(path.GetString()), out DirectoryNode dirNode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
directory = new MemoryDirectory(dirNode, mode);
|
||||
@ -116,11 +83,7 @@ namespace LibHac.Fs
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out file);
|
||||
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = FsTable.GetFile(normalizedPath, out FileNode fileNode);
|
||||
Result rc = FsTable.GetFile(new U8Span(path.GetString()), out FileNode fileNode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
file = new MemoryFile(mode, fileNode.File);
|
||||
@ -130,47 +93,25 @@ namespace LibHac.Fs
|
||||
|
||||
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedCurrentPath);
|
||||
Unsafe.SkipInit(out FsPath normalizedNewPath);
|
||||
|
||||
Result rc = PathNormalizer.Normalize(normalizedCurrentPath.Str, out _, currentPath, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = PathNormalizer.Normalize(normalizedNewPath.Str, out _, newPath, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return FsTable.RenameDirectory(normalizedCurrentPath, normalizedNewPath);
|
||||
return FsTable.RenameDirectory(new U8Span(currentPath.GetString()), new U8Span(newPath.GetString()));
|
||||
}
|
||||
|
||||
protected override Result DoRenameFile(in Path currentPath, in Path newPath)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedCurrentPath);
|
||||
Unsafe.SkipInit(out FsPath normalizedNewPath);
|
||||
|
||||
Result rc = PathNormalizer.Normalize(normalizedCurrentPath.Str, out _, currentPath, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = PathNormalizer.Normalize(normalizedNewPath.Str, out _, newPath, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return FsTable.RenameFile(normalizedCurrentPath, normalizedNewPath);
|
||||
return FsTable.RenameFile(new U8Span(currentPath.GetString()), new U8Span(newPath.GetString()));
|
||||
}
|
||||
|
||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out entryType);
|
||||
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (FsTable.GetFile(normalizedPath, out _).IsSuccess())
|
||||
if (FsTable.GetFile(new U8Span(path.GetString()), out _).IsSuccess())
|
||||
{
|
||||
entryType = DirectoryEntryType.File;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (FsTable.GetDirectory(normalizedPath, out _).IsSuccess())
|
||||
if (FsTable.GetDirectory(new U8Span(path.GetString()), out _).IsSuccess())
|
||||
{
|
||||
entryType = DirectoryEntryType.Directory;
|
||||
return Result.Success;
|
||||
@ -184,21 +125,17 @@ namespace LibHac.Fs
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoGetFileAttributes(out NxFileAttributes attributes, U8Span path)
|
||||
protected override Result DoGetFileAttributes(out NxFileAttributes attributes, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out attributes);
|
||||
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (FsTable.GetFile(normalizedPath, out FileNode file).IsSuccess())
|
||||
if (FsTable.GetFile(new U8Span(path.GetString()), out FileNode file).IsSuccess())
|
||||
{
|
||||
attributes = file.Attributes;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (FsTable.GetDirectory(normalizedPath, out DirectoryNode dir).IsSuccess())
|
||||
if (FsTable.GetDirectory(new U8Span(path.GetString()), out DirectoryNode dir).IsSuccess())
|
||||
{
|
||||
attributes = dir.Attributes;
|
||||
return Result.Success;
|
||||
@ -207,19 +144,15 @@ namespace LibHac.Fs
|
||||
return ResultFs.PathNotFound.Log();
|
||||
}
|
||||
|
||||
protected override Result DoSetFileAttributes(U8Span path, NxFileAttributes attributes)
|
||||
protected override Result DoSetFileAttributes(in Path path, NxFileAttributes attributes)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (FsTable.GetFile(normalizedPath, out FileNode file).IsSuccess())
|
||||
if (FsTable.GetFile(new U8Span(path.GetString()), out FileNode file).IsSuccess())
|
||||
{
|
||||
file.Attributes = attributes;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (FsTable.GetDirectory(normalizedPath, out DirectoryNode dir).IsSuccess())
|
||||
if (FsTable.GetDirectory(new U8Span(path.GetString()), out DirectoryNode dir).IsSuccess())
|
||||
{
|
||||
dir.Attributes = attributes;
|
||||
return Result.Success;
|
||||
@ -228,15 +161,11 @@ namespace LibHac.Fs
|
||||
return ResultFs.PathNotFound.Log();
|
||||
}
|
||||
|
||||
protected override Result DoGetFileSize(out long fileSize, U8Span path)
|
||||
protected override Result DoGetFileSize(out long fileSize, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out fileSize);
|
||||
|
||||
Unsafe.SkipInit(out FsPath normalizedPath);
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath.Str, out _, path, false, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (FsTable.GetFile(normalizedPath, out FileNode file).IsSuccess())
|
||||
if (FsTable.GetFile(new U8Span(path.GetString()), out FileNode file).IsSuccess())
|
||||
{
|
||||
return file.File.GetSize(out fileSize);
|
||||
}
|
||||
|
@ -1,266 +1,280 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.FsSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IFileSystem"/> that uses a directory of another <see cref="IFileSystem"/> as its root directory.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
|
||||
public class SubdirectoryFileSystem : IFileSystem
|
||||
{
|
||||
private IFileSystem BaseFileSystem { get; }
|
||||
private ReferenceCountedDisposable<IFileSystem> BaseFileSystemShared { get; }
|
||||
private U8String RootPath { get; set; }
|
||||
private bool PreserveUnc { get; }
|
||||
private IFileSystem _baseFileSystem;
|
||||
private ReferenceCountedDisposable<IFileSystem> _baseFileSystemShared;
|
||||
private Path.Stored _rootPath;
|
||||
|
||||
public static Result CreateNew(out SubdirectoryFileSystem created, IFileSystem baseFileSystem, U8Span rootPath, bool preserveUnc = false)
|
||||
public SubdirectoryFileSystem(IFileSystem baseFileSystem)
|
||||
{
|
||||
var obj = new SubdirectoryFileSystem(baseFileSystem, preserveUnc);
|
||||
Result rc = obj.Initialize(rootPath);
|
||||
|
||||
if (rc.IsSuccess())
|
||||
{
|
||||
created = obj;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
obj.Dispose();
|
||||
UnsafeHelpers.SkipParamInit(out created);
|
||||
return rc;
|
||||
_baseFileSystem = baseFileSystem;
|
||||
}
|
||||
|
||||
public SubdirectoryFileSystem(IFileSystem baseFileSystem, bool preserveUnc = false)
|
||||
public SubdirectoryFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem)
|
||||
{
|
||||
BaseFileSystem = baseFileSystem;
|
||||
PreserveUnc = preserveUnc;
|
||||
}
|
||||
|
||||
public SubdirectoryFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, bool preserveUnc = false)
|
||||
{
|
||||
BaseFileSystemShared = Shared.Move(ref baseFileSystem);
|
||||
BaseFileSystem = BaseFileSystemShared.Target;
|
||||
PreserveUnc = preserveUnc;
|
||||
_baseFileSystemShared = Shared.Move(ref baseFileSystem);
|
||||
_baseFileSystem = _baseFileSystemShared.Target;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
BaseFileSystemShared?.Dispose();
|
||||
ReferenceCountedDisposable<IFileSystem> sharedFs = Shared.Move(ref _baseFileSystemShared);
|
||||
sharedFs?.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public Result Initialize(U8Span rootPath)
|
||||
public Result Initialize(in Path rootPath)
|
||||
{
|
||||
if (StringUtils.GetLength(rootPath, PathTools.MaxPathLength + 1) > PathTools.MaxPathLength)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
Span<byte> normalizedPath = stackalloc byte[PathTools.MaxPathLength + 2];
|
||||
|
||||
Result rc = PathNormalizer.Normalize(normalizedPath, out long normalizedPathLen, rootPath, PreserveUnc, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Ensure a trailing separator
|
||||
if (!PathNormalizer.IsSeparator(normalizedPath[(int)normalizedPathLen - 1]))
|
||||
{
|
||||
Debug.Assert(normalizedPathLen + 2 <= normalizedPath.Length);
|
||||
|
||||
normalizedPath[(int)normalizedPathLen] = StringTraits.DirectorySeparator;
|
||||
normalizedPath[(int)normalizedPathLen + 1] = StringTraits.NullTerminator;
|
||||
normalizedPathLen++;
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[normalizedPathLen + 1];
|
||||
normalizedPath.Slice(0, (int)normalizedPathLen).CopyTo(buffer);
|
||||
RootPath = new U8String(buffer);
|
||||
|
||||
return Result.Success;
|
||||
return _rootPath.Initialize(in rootPath);
|
||||
}
|
||||
|
||||
private Result ResolveFullPath(Span<byte> outPath, U8Span relativePath)
|
||||
private Result ResolveFullPath(ref Path outPath, in Path relativePath)
|
||||
{
|
||||
if (RootPath.Length + StringUtils.GetLength(relativePath, PathTools.MaxPathLength + 1) > outPath.Length)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
// Copy root path to the output
|
||||
RootPath.Value.CopyTo(outPath);
|
||||
|
||||
// Copy the normalized relative path to the output
|
||||
return PathNormalizer.Normalize(outPath.Slice(RootPath.Length - 2), out _, relativePath, PreserveUnc, false);
|
||||
}
|
||||
|
||||
protected override Result DoCreateDirectory(in Path path)
|
||||
{
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.CreateDirectory(new U8Span(fullPath));
|
||||
}
|
||||
|
||||
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option)
|
||||
{
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.CreateFile(new U8Span(fullPath), size, option);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectory(in Path path)
|
||||
{
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.DeleteDirectory(new U8Span(fullPath));
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectoryRecursively(in Path path)
|
||||
{
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.DeleteDirectoryRecursively(new U8Span(fullPath));
|
||||
}
|
||||
|
||||
protected override Result DoCleanDirectoryRecursively(in Path path)
|
||||
{
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.CleanDirectoryRecursively(new U8Span(fullPath));
|
||||
}
|
||||
|
||||
protected override Result DoDeleteFile(in Path path)
|
||||
{
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.DeleteFile(new U8Span(fullPath));
|
||||
}
|
||||
|
||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out directory);
|
||||
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.OpenDirectory(out directory, new U8Span(fullPath), mode);
|
||||
}
|
||||
|
||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out file);
|
||||
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.OpenFile(out file, new U8Span(fullPath), mode);
|
||||
}
|
||||
|
||||
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
|
||||
{
|
||||
Span<byte> fullOldPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Span<byte> fullNewPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
|
||||
Result rc = ResolveFullPath(fullOldPath, currentPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = ResolveFullPath(fullNewPath, newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.RenameDirectory(new U8Span(fullOldPath), new U8Span(fullNewPath));
|
||||
}
|
||||
|
||||
protected override Result DoRenameFile(in Path currentPath, in Path newPath)
|
||||
{
|
||||
Span<byte> fullOldPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Span<byte> fullNewPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
|
||||
Result rc = ResolveFullPath(fullOldPath, currentPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = ResolveFullPath(fullNewPath, newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.RenameFile(new U8Span(fullOldPath), new U8Span(fullNewPath));
|
||||
Path rootPath = _rootPath.GetPath();
|
||||
return outPath.Combine(in rootPath, in relativePath);
|
||||
}
|
||||
|
||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out entryType);
|
||||
|
||||
Unsafe.SkipInit(out FsPath fullPath);
|
||||
|
||||
Result rc = ResolveFullPath(fullPath.Str, path);
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.GetEntryType(out entryType, fullPath);
|
||||
}
|
||||
rc = _baseFileSystem.GetEntryType(out entryType, in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
protected override Result DoCommit()
|
||||
{
|
||||
return BaseFileSystem.Commit();
|
||||
}
|
||||
|
||||
protected override Result DoCommitProvisionally(long counter)
|
||||
{
|
||||
return BaseFileSystem.CommitProvisionally(counter);
|
||||
}
|
||||
|
||||
protected override Result DoRollback()
|
||||
{
|
||||
return BaseFileSystem.Rollback();
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out freeSpace);
|
||||
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.GetFreeSpaceSize(out freeSpace, new U8Span(fullPath));
|
||||
rc = _baseFileSystem.GetFreeSpaceSize(out freeSpace, in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out totalSpace);
|
||||
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.GetTotalSpaceSize(out totalSpace, new U8Span(fullPath));
|
||||
rc = _baseFileSystem.GetTotalSpaceSize(out totalSpace, in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out timeStamp);
|
||||
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, new U8Span(fullPath));
|
||||
rc = _baseFileSystem.GetFileTimeStampRaw(out timeStamp, in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoOpenFile(out IFile file, in Path path, OpenMode mode)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out file);
|
||||
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.OpenFile(out file, in fullPath, mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoOpenDirectory(out IDirectory directory, in Path path, OpenDirectoryMode mode)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out directory);
|
||||
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.OpenDirectory(out directory, in fullPath, mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option)
|
||||
{
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.CreateFile(in fullPath, size, option);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoDeleteFile(in Path path)
|
||||
{
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.DeleteFile(in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoCreateDirectory(in Path path)
|
||||
{
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.CreateDirectory(in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectory(in Path path)
|
||||
{
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.DeleteDirectory(in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectoryRecursively(in Path path)
|
||||
{
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.DeleteDirectoryRecursively(in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoCleanDirectoryRecursively(in Path path)
|
||||
{
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.CleanDirectoryRecursively(in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoRenameFile(in Path currentPath, in Path newPath)
|
||||
{
|
||||
var currentFullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref currentFullPath, in currentPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var newFullPath = new Path();
|
||||
rc = ResolveFullPath(ref newFullPath, in newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.RenameFile(in currentFullPath, in newFullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
currentFullPath.Dispose();
|
||||
newFullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
|
||||
{
|
||||
var currentFullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref currentFullPath, in currentPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var newFullPath = new Path();
|
||||
rc = ResolveFullPath(ref newFullPath, in newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.RenameDirectory(in currentFullPath, in newFullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
currentFullPath.Dispose();
|
||||
newFullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
|
||||
in Path path)
|
||||
{
|
||||
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
|
||||
Result rc = ResolveFullPath(fullPath, path);
|
||||
var fullPath = new Path();
|
||||
Result rc = ResolveFullPath(ref fullPath, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, new U8Span(fullPath));
|
||||
rc = _baseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, in fullPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fullPath.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoCommit()
|
||||
{
|
||||
return _baseFileSystem.Commit();
|
||||
}
|
||||
|
||||
protected override Result DoCommitProvisionally(long counter)
|
||||
{
|
||||
return _baseFileSystem.CommitProvisionally(counter);
|
||||
}
|
||||
|
||||
protected override Result DoRollback()
|
||||
{
|
||||
return _baseFileSystem.Rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,13 +65,22 @@ namespace LibHac
|
||||
{
|
||||
var concatFs = new ConcatenationFileSystem(fileSystem);
|
||||
SubdirectoryFileSystem saveDirFs = null;
|
||||
SubdirectoryFileSystem contentDirFs = null;
|
||||
|
||||
if (concatFs.DirectoryExists("/save"))
|
||||
{
|
||||
SubdirectoryFileSystem.CreateNew(out saveDirFs, concatFs, "/save".ToU8String()).ThrowIfFailure();
|
||||
var savePath = new Fs.Path();
|
||||
PathFunctions.SetUpFixedPath(ref savePath, "/save".ToU8String());
|
||||
|
||||
saveDirFs = new SubdirectoryFileSystem(concatFs);
|
||||
saveDirFs.Initialize(in savePath).ThrowIfFailure();
|
||||
}
|
||||
|
||||
SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem contentDirFs, concatFs, "/Contents".ToU8String()).ThrowIfFailure();
|
||||
var contentsPath = new Fs.Path();
|
||||
PathFunctions.SetUpFixedPath(ref contentsPath, "/Contents".ToU8String());
|
||||
|
||||
contentDirFs = new SubdirectoryFileSystem(concatFs);
|
||||
contentDirFs.Initialize(in contentsPath).ThrowIfFailure();
|
||||
|
||||
return new SwitchFs(keySet, contentDirFs, saveDirFs);
|
||||
}
|
||||
|
@ -20,8 +20,11 @@ namespace LibHac.Tests.Fs
|
||||
baseFs.CreateDirectory("/sub");
|
||||
baseFs.CreateDirectory("/sub/path");
|
||||
|
||||
var rootPath = new Path();
|
||||
PathFunctions.SetUpFixedPath(ref rootPath, "/sub/path".ToU8String());
|
||||
|
||||
var subFs = new SubdirectoryFileSystem(baseFs);
|
||||
subFs.Initialize("/sub/path".ToU8String()).ThrowIfFailure();
|
||||
subFs.Initialize(in rootPath).ThrowIfFailure();
|
||||
|
||||
return (baseFs, subFs);
|
||||
}
|
||||
@ -55,8 +58,11 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
var baseFs = new InMemoryFileSystem();
|
||||
|
||||
var rootPath = new Path();
|
||||
PathFunctions.SetUpFixedPath(ref rootPath, "/".ToU8String());
|
||||
|
||||
var subFs = new SubdirectoryFileSystem(baseFs);
|
||||
subFs.Initialize("/".ToU8String()).ThrowIfFailure();
|
||||
subFs.Initialize(in rootPath).ThrowIfFailure();
|
||||
return subFs;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user