mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Update FileSystemInterfaceAdapter
This commit is contained in:
parent
8e162cc3c8
commit
4934b1cbef
6 changed files with 654 additions and 448 deletions
|
@ -39,6 +39,7 @@ namespace LibHac.Fs
|
|||
private int _writeBufferLength;
|
||||
private bool _isNormalized;
|
||||
|
||||
// Todo: Hack around "using" variables being read only
|
||||
public void Dispose()
|
||||
{
|
||||
byte[] writeBuffer = Shared.Move(ref _writeBuffer);
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Sf;
|
||||
using IDirectory = LibHac.Fs.Fsa.IDirectory;
|
||||
using IDirectorySf = LibHac.FsSrv.Sf.IDirectory;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
public class DirectoryInterfaceAdapter : IDirectorySf
|
||||
{
|
||||
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> ParentFs { get; }
|
||||
private IDirectory BaseDirectory { get; }
|
||||
|
||||
public DirectoryInterfaceAdapter(IDirectory baseDirectory,
|
||||
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem)
|
||||
{
|
||||
BaseDirectory = baseDirectory;
|
||||
ParentFs = parentFileSystem;
|
||||
parentFileSystem = null;
|
||||
}
|
||||
|
||||
public Result Read(out long entriesRead, OutBuffer entryBuffer)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out entriesRead);
|
||||
|
||||
Span<DirectoryEntry> entries = MemoryMarshal.Cast<byte, DirectoryEntry>(entryBuffer.Buffer);
|
||||
|
||||
Result rc = Result.Success;
|
||||
long tmpEntriesRead = 0;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = BaseDirectory.Read(out tmpEntriesRead, entries);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
entriesRead = tmpEntriesRead;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetEntryCount(out long entryCount)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out entryCount);
|
||||
|
||||
Result rc = BaseDirectory.GetEntryCount(out long tmpEntryCount);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
entryCount = tmpEntryCount;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BaseDirectory?.Dispose();
|
||||
ParentFs?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Sf;
|
||||
using IFile = LibHac.Fs.Fsa.IFile;
|
||||
using IFileSf = LibHac.FsSrv.Sf.IFile;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
public class FileInterfaceAdapter : IFileSf
|
||||
{
|
||||
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> ParentFs { get; }
|
||||
private IFile BaseFile { get; }
|
||||
|
||||
public FileInterfaceAdapter(IFile baseFile,
|
||||
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem)
|
||||
{
|
||||
BaseFile = baseFile;
|
||||
ParentFs = parentFileSystem;
|
||||
parentFileSystem = null;
|
||||
}
|
||||
|
||||
public Result Read(out long bytesRead, long offset, OutBuffer destination, long size, ReadOption option)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out bytesRead);
|
||||
|
||||
if (offset < 0)
|
||||
return ResultFs.InvalidOffset.Log();
|
||||
|
||||
if (destination.Size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
Result rc = Result.Success;
|
||||
long tmpBytesRead = 0;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = BaseFile.Read(out tmpBytesRead, offset, destination.Buffer.Slice(0, (int)size), option);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
bytesRead = tmpBytesRead;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Write(long offset, InBuffer source, long size, WriteOption option)
|
||||
{
|
||||
if (offset < 0)
|
||||
return ResultFs.InvalidOffset.Log();
|
||||
|
||||
if (source.Size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
// Note: Thread priority is temporarily increased when writing in FS
|
||||
|
||||
return BaseFile.Write(offset, source.Buffer.Slice(0, (int)size), option);
|
||||
}
|
||||
|
||||
public Result Flush()
|
||||
{
|
||||
return BaseFile.Flush();
|
||||
}
|
||||
|
||||
public Result SetSize(long size)
|
||||
{
|
||||
if (size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
return BaseFile.SetSize(size);
|
||||
}
|
||||
|
||||
public Result GetSize(out long size)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out size);
|
||||
|
||||
Result rc = Result.Success;
|
||||
long tmpSize = 0;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = BaseFile.GetSize(out tmpSize);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
size = tmpSize;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out rangeInfo);
|
||||
rangeInfo.Clear();
|
||||
|
||||
if (operationId == (int)OperationId.InvalidateCache)
|
||||
{
|
||||
Result rc = BaseFile.OperateRange(Span<byte>.Empty, OperationId.InvalidateCache, offset, size,
|
||||
ReadOnlySpan<byte>.Empty);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
else if (operationId == (int)OperationId.QueryRange)
|
||||
{
|
||||
Unsafe.SkipInit(out QueryRangeInfo info);
|
||||
|
||||
Result rc = BaseFile.OperateRange(SpanHelpers.AsByteSpan(ref info), OperationId.QueryRange, offset,
|
||||
size, ReadOnlySpan<byte>.Empty);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rangeInfo.Merge(in info);
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BaseFile?.Dispose();
|
||||
ParentFs?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,292 +1,644 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Util;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Sf;
|
||||
|
||||
using IFile = LibHac.Fs.Fsa.IFile;
|
||||
using IFileSf = LibHac.FsSrv.Sf.IFile;
|
||||
using IDirectory = LibHac.Fs.Fsa.IDirectory;
|
||||
using IDirectorySf = LibHac.FsSrv.Sf.IDirectory;
|
||||
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
|
||||
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
|
||||
using IFileSf = LibHac.FsSrv.Sf.IFile;
|
||||
using IDirectorySf = LibHac.FsSrv.Sf.IDirectory;
|
||||
using Path = LibHac.FsSrv.Sf.Path;
|
||||
using PathSf = LibHac.FsSrv.Sf.Path;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps an <see cref="IFile"/> to allow interfacing with it via the <see cref="IFileSf"/> interface over IPC.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
|
||||
public class FileInterfaceAdapter : IFileSf
|
||||
{
|
||||
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
|
||||
private IFile _baseFile;
|
||||
private bool _allowAllOperations;
|
||||
|
||||
public FileInterfaceAdapter(IFile baseFile,
|
||||
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem, bool allowAllOperations)
|
||||
{
|
||||
_baseFile = baseFile;
|
||||
_parentFs = Shared.Move(ref parentFileSystem);
|
||||
_allowAllOperations = allowAllOperations;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseFile?.Dispose();
|
||||
_parentFs?.Dispose();
|
||||
}
|
||||
|
||||
public Result Read(out long bytesRead, long offset, OutBuffer destination, long size, ReadOption option)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out bytesRead);
|
||||
|
||||
if (offset < 0)
|
||||
return ResultFs.InvalidOffset.Log();
|
||||
|
||||
if (destination.Size < 0 || destination.Size < (int)size)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
Result rc = Result.Success;
|
||||
long tmpBytesRead = 0;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseFile.Read(out tmpBytesRead, offset, destination.Buffer.Slice(0, (int)size), option);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
bytesRead = tmpBytesRead;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Write(long offset, InBuffer source, long size, WriteOption option)
|
||||
{
|
||||
if (offset < 0)
|
||||
return ResultFs.InvalidOffset.Log();
|
||||
|
||||
if (source.Size < 0 || source.Size < (int)size)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
using var scopedPriorityChanger =
|
||||
new ScopedThreadPriorityChangerByAccessPriority(ScopedThreadPriorityChangerByAccessPriority.AccessMode.Write);
|
||||
|
||||
return _baseFile.Write(offset, source.Buffer.Slice(0, (int)size), option);
|
||||
}
|
||||
|
||||
public Result Flush()
|
||||
{
|
||||
return _baseFile.Flush();
|
||||
}
|
||||
|
||||
public Result SetSize(long size)
|
||||
{
|
||||
if (size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
return _baseFile.SetSize(size);
|
||||
}
|
||||
|
||||
public Result GetSize(out long size)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out size);
|
||||
|
||||
Result rc = Result.Success;
|
||||
long tmpSize = 0;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseFile.GetSize(out tmpSize);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
size = tmpSize;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out rangeInfo);
|
||||
rangeInfo.Clear();
|
||||
|
||||
if (operationId == (int)OperationId.QueryRange)
|
||||
{
|
||||
Unsafe.SkipInit(out QueryRangeInfo info);
|
||||
|
||||
Result rc = _baseFile.OperateRange(SpanHelpers.AsByteSpan(ref info), OperationId.QueryRange, offset,
|
||||
size, ReadOnlySpan<byte>.Empty);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rangeInfo.Merge(in info);
|
||||
}
|
||||
else if (operationId == (int)OperationId.InvalidateCache)
|
||||
{
|
||||
Result rc = _baseFile.OperateRange(Span<byte>.Empty, OperationId.InvalidateCache, offset, size,
|
||||
ReadOnlySpan<byte>.Empty);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OperateRangeWithBuffer(OutBuffer outBuffer, InBuffer inBuffer, int operationId, long offset, long size)
|
||||
{
|
||||
static Result PermissionCheck(OperationId operationId, FileInterfaceAdapter fileAdapter)
|
||||
{
|
||||
if (operationId == OperationId.QueryUnpreparedRange ||
|
||||
operationId == OperationId.QueryLazyLoadCompletionRate ||
|
||||
operationId == OperationId.SetLazyLoadPriority)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (!fileAdapter._allowAllOperations)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
Result rc = PermissionCheck((OperationId)operationId, this);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFile.OperateRange(outBuffer.Buffer, (OperationId)operationId, offset, size, inBuffer.Buffer);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps an <see cref="IDirectory"/> to allow interfacing with it via the <see cref="IDirectorySf"/> interface over IPC.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
|
||||
public class DirectoryInterfaceAdapter : IDirectorySf
|
||||
{
|
||||
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
|
||||
private IDirectory _baseDirectory;
|
||||
|
||||
public DirectoryInterfaceAdapter(IDirectory baseDirectory,
|
||||
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem)
|
||||
{
|
||||
_baseDirectory = baseDirectory;
|
||||
_parentFs = Shared.Move(ref parentFileSystem);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseDirectory?.Dispose();
|
||||
_parentFs?.Dispose();
|
||||
}
|
||||
|
||||
public Result Read(out long entriesRead, OutBuffer entryBuffer)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out entriesRead);
|
||||
|
||||
Span<DirectoryEntry> entries = MemoryMarshal.Cast<byte, DirectoryEntry>(entryBuffer.Buffer);
|
||||
|
||||
Result rc = Result.Success;
|
||||
long numRead = 0;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseDirectory.Read(out numRead, entries);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
entriesRead = numRead;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetEntryCount(out long entryCount)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out entryCount);
|
||||
|
||||
Result rc = _baseDirectory.GetEntryCount(out long count);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
entryCount = count;
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps an <see cref="IFileSystem"/> to allow interfacing with it via the <see cref="IFileSystemSf"/> interface over IPC.
|
||||
/// All incoming paths are normalized before they are passed to the base <see cref="IFileSystem"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
|
||||
public class FileSystemInterfaceAdapter : IFileSystemSf
|
||||
{
|
||||
private ReferenceCountedDisposable<IFileSystem> BaseFileSystem { get; }
|
||||
private bool IsHostFsRoot { get; }
|
||||
private ReferenceCountedDisposable<IFileSystem> _baseFileSystem;
|
||||
private PathFlags _pathFlags;
|
||||
|
||||
// This field is always false in FS 12.0.0. Not sure what it's actually used for.
|
||||
private bool _allowAllOperations;
|
||||
|
||||
// In FS, FileSystemInterfaceAdapter is derived from ISharedObject, so that's used for ref-counting when
|
||||
// creating files and directories. We don't have an ISharedObject, so a self-reference is used instead.
|
||||
private ReferenceCountedDisposable<FileSystemInterfaceAdapter>.WeakReference _selfReference;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="FileSystemInterfaceAdapter"/> by creating
|
||||
/// a new reference to <paramref name="fileSystem"/>.
|
||||
/// </summary>
|
||||
/// <param name="fileSystem">The base file system.</param>
|
||||
/// <param name="isHostFsRoot">Does the base file system come from the root directory of a host file system?</param>
|
||||
private FileSystemInterfaceAdapter(ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
bool isHostFsRoot = false)
|
||||
{
|
||||
BaseFileSystem = fileSystem.AddReference();
|
||||
IsHostFsRoot = isHostFsRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="FileSystemInterfaceAdapter"/> by moving the file system object.
|
||||
/// Avoids allocations from incrementing and then decrementing the ref-count.
|
||||
/// </summary>
|
||||
/// <param name="fileSystem">The base file system. Will be null upon returning.</param>
|
||||
/// <param name="isHostFsRoot">Does the base file system come from the root directory of a host file system?</param>
|
||||
private FileSystemInterfaceAdapter(ref ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
bool isHostFsRoot = false)
|
||||
bool allowAllOperations)
|
||||
{
|
||||
BaseFileSystem = fileSystem;
|
||||
fileSystem = null;
|
||||
IsHostFsRoot = isHostFsRoot;
|
||||
_baseFileSystem = Shared.Move(ref fileSystem);
|
||||
_allowAllOperations = allowAllOperations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="FileSystemInterfaceAdapter"/>, creating a copy of the input file system object.
|
||||
/// </summary>
|
||||
/// <param name="baseFileSystem">The base file system.</param>
|
||||
/// <param name="isHostFsRoot">Does the base file system come from the root directory of a host file system?</param>
|
||||
public static ReferenceCountedDisposable<FileSystemInterfaceAdapter> CreateShared(
|
||||
ReferenceCountedDisposable<IFileSystem> baseFileSystem, bool isHostFsRoot = false)
|
||||
private FileSystemInterfaceAdapter(ref ReferenceCountedDisposable<IFileSystem> fileSystem, PathFlags flags,
|
||||
bool allowAllOperations)
|
||||
{
|
||||
var adapter = new FileSystemInterfaceAdapter(baseFileSystem, isHostFsRoot);
|
||||
|
||||
return ReferenceCountedDisposable<FileSystemInterfaceAdapter>.Create(adapter, out adapter._selfReference);
|
||||
_baseFileSystem = Shared.Move(ref fileSystem);
|
||||
_pathFlags = flags;
|
||||
_allowAllOperations = allowAllOperations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="FileSystemInterfaceAdapter"/> cast to an <see cref="IFileSystemSf"/>
|
||||
/// by moving the input file system object. Avoids allocations from incrementing and then decrementing the ref-count.
|
||||
/// </summary>
|
||||
/// <param name="baseFileSystem">The base file system. Will be null upon returning.</param>
|
||||
/// <param name="isHostFsRoot">Does the base file system come from the root directory of a host file system?</param>
|
||||
public static ReferenceCountedDisposable<IFileSystemSf> CreateShared(
|
||||
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, bool isHostFsRoot = false)
|
||||
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, bool allowAllOperations)
|
||||
{
|
||||
var adapter = new FileSystemInterfaceAdapter(ref baseFileSystem, isHostFsRoot);
|
||||
|
||||
return ReferenceCountedDisposable<IFileSystemSf>.Create(adapter, out adapter._selfReference);
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> RootDir => new[] { (byte)'/' };
|
||||
|
||||
public Result GetImpl(out ReferenceCountedDisposable<IFileSystem> fileSystem)
|
||||
{
|
||||
fileSystem = BaseFileSystem.AddReference();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CreateFile(in Path path, long size, int option)
|
||||
{
|
||||
if (size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
return BaseFileSystem.Target.CreateFile(normalizer.Path, size, (CreateFileOptions)option);
|
||||
}
|
||||
|
||||
public Result DeleteFile(in Path path)
|
||||
{
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
return BaseFileSystem.Target.DeleteFile(normalizer.Path);
|
||||
}
|
||||
|
||||
public Result CreateDirectory(in Path path)
|
||||
{
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
if (StringUtils.Compare(RootDir, normalizer.Path) == 0)
|
||||
return ResultFs.PathAlreadyExists.Log();
|
||||
|
||||
return BaseFileSystem.Target.CreateDirectory(normalizer.Path);
|
||||
}
|
||||
|
||||
public Result DeleteDirectory(in Path path)
|
||||
{
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
if (StringUtils.Compare(RootDir, normalizer.Path) == 0)
|
||||
return ResultFs.DirectoryNotDeletable.Log();
|
||||
|
||||
return BaseFileSystem.Target.DeleteDirectory(normalizer.Path);
|
||||
}
|
||||
|
||||
public Result DeleteDirectoryRecursively(in Path path)
|
||||
{
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
if (StringUtils.Compare(RootDir, normalizer.Path) == 0)
|
||||
return ResultFs.DirectoryNotDeletable.Log();
|
||||
|
||||
return BaseFileSystem.Target.DeleteDirectoryRecursively(normalizer.Path);
|
||||
}
|
||||
|
||||
public Result RenameFile(in Path oldPath, in Path newPath)
|
||||
{
|
||||
using var normalizerOldPath = new PathNormalizer(new U8Span(oldPath.Str), GetPathNormalizerOption());
|
||||
if (normalizerOldPath.Result.IsFailure()) return normalizerOldPath.Result;
|
||||
|
||||
using var normalizerNewPath = new PathNormalizer(new U8Span(newPath.Str), GetPathNormalizerOption());
|
||||
if (normalizerNewPath.Result.IsFailure()) return normalizerNewPath.Result;
|
||||
|
||||
return BaseFileSystem.Target.RenameFile(new U8Span(normalizerOldPath.Path),
|
||||
new U8Span(normalizerNewPath.Path));
|
||||
}
|
||||
|
||||
public Result RenameDirectory(in Path oldPath, in Path newPath)
|
||||
{
|
||||
using var normalizerOldPath = new PathNormalizer(new U8Span(oldPath.Str), GetPathNormalizerOption());
|
||||
if (normalizerOldPath.Result.IsFailure()) return normalizerOldPath.Result;
|
||||
|
||||
using var normalizerNewPath = new PathNormalizer(new U8Span(newPath.Str), GetPathNormalizerOption());
|
||||
if (normalizerNewPath.Result.IsFailure()) return normalizerNewPath.Result;
|
||||
|
||||
if (PathUtility.IsSubPath(normalizerOldPath.Path, normalizerNewPath.Path))
|
||||
return ResultFs.DirectoryNotRenamable.Log();
|
||||
|
||||
return BaseFileSystem.Target.RenameDirectory(normalizerOldPath.Path, normalizerNewPath.Path);
|
||||
}
|
||||
|
||||
public Result GetEntryType(out uint entryType, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out entryType);
|
||||
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
ref DirectoryEntryType type = ref Unsafe.As<uint, DirectoryEntryType>(ref entryType);
|
||||
|
||||
return BaseFileSystem.Target.GetEntryType(out type, new U8Span(normalizer.Path));
|
||||
}
|
||||
|
||||
public Result OpenFile(out ReferenceCountedDisposable<IFileSf> file, in Path path, uint mode)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out file);
|
||||
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
Result rc = Result.Success;
|
||||
IFile fileInterface = null;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> sharedAdapter = null;
|
||||
try
|
||||
{
|
||||
rc = BaseFileSystem.Target.OpenFile(out fileInterface, new U8Span(normalizer.Path), (OpenMode)mode);
|
||||
var adapter = new FileSystemInterfaceAdapter(ref baseFileSystem, allowAllOperations);
|
||||
sharedAdapter = new ReferenceCountedDisposable<FileSystemInterfaceAdapter>(adapter);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
adapter._selfReference =
|
||||
new ReferenceCountedDisposable<FileSystemInterfaceAdapter>.WeakReference(sharedAdapter);
|
||||
|
||||
return sharedAdapter.AddReference<IFileSystemSf>();
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.TryAddReference();
|
||||
var adapter = new FileInterfaceAdapter(fileInterface, ref selfReference);
|
||||
file = new ReferenceCountedDisposable<IFileSf>(adapter);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> directory, in Path path, uint mode)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out directory);
|
||||
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
Result rc = Result.Success;
|
||||
IDirectory dirInterface = null;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
finally
|
||||
{
|
||||
rc = BaseFileSystem.Target.OpenDirectory(out dirInterface, new U8Span(normalizer.Path), (OpenDirectoryMode)mode);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
sharedAdapter?.Dispose();
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.TryAddReference();
|
||||
var adapter = new DirectoryInterfaceAdapter(dirInterface, ref selfReference);
|
||||
directory = new ReferenceCountedDisposable<IDirectorySf>(adapter);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Commit()
|
||||
public static ReferenceCountedDisposable<IFileSystemSf> CreateShared(PathFlags flags,
|
||||
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, bool allowAllOperations)
|
||||
{
|
||||
return BaseFileSystem.Target.Commit();
|
||||
}
|
||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> sharedAdapter = null;
|
||||
try
|
||||
{
|
||||
var adapter = new FileSystemInterfaceAdapter(ref baseFileSystem, flags, allowAllOperations);
|
||||
sharedAdapter = new ReferenceCountedDisposable<FileSystemInterfaceAdapter>(adapter);
|
||||
|
||||
public Result GetFreeSpaceSize(out long freeSpace, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out freeSpace);
|
||||
adapter._selfReference =
|
||||
new ReferenceCountedDisposable<FileSystemInterfaceAdapter>.WeakReference(sharedAdapter);
|
||||
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
return BaseFileSystem.Target.GetFreeSpaceSize(out freeSpace, normalizer.Path);
|
||||
}
|
||||
|
||||
public Result GetTotalSpaceSize(out long totalSpace, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out totalSpace);
|
||||
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
return BaseFileSystem.Target.GetTotalSpaceSize(out totalSpace, normalizer.Path);
|
||||
}
|
||||
|
||||
public Result CleanDirectoryRecursively(in Path path)
|
||||
{
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
return BaseFileSystem.Target.CleanDirectoryRecursively(normalizer.Path);
|
||||
}
|
||||
|
||||
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out timeStamp);
|
||||
|
||||
using var normalizer = new PathNormalizer(new U8Span(path.Str), GetPathNormalizerOption());
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
return BaseFileSystem.Target.GetFileTimeStampRaw(out timeStamp, normalizer.Path);
|
||||
}
|
||||
|
||||
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, int queryId, in Path path)
|
||||
{
|
||||
return BaseFileSystem.Target.QueryEntry(outBuffer, inBuffer, (QueryId)queryId, new U8Span(path.Str));
|
||||
return sharedAdapter.AddReference<IFileSystemSf>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
sharedAdapter?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BaseFileSystem?.Dispose();
|
||||
ReferenceCountedDisposable<IFileSystem> tempFs = Shared.Move(ref _baseFileSystem);
|
||||
tempFs?.Dispose();
|
||||
}
|
||||
|
||||
private PathNormalizer.Option GetPathNormalizerOption()
|
||||
private static ReadOnlySpan<byte> RootDir => new[] { (byte)'/' };
|
||||
|
||||
private Result SetUpPath(ref Path fsPath, in PathSf sfPath)
|
||||
{
|
||||
return IsHostFsRoot ? PathNormalizer.Option.PreserveUnc : PathNormalizer.Option.None;
|
||||
Result rc;
|
||||
|
||||
if (_pathFlags.IsWindowsPathAllowed())
|
||||
{
|
||||
rc = fsPath.InitializeWithReplaceUnc(sfPath.Str);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = fsPath.Initialize(sfPath.Str);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
rc = fsPath.Normalize(_pathFlags);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CreateFile(in PathSf path, long size, int option)
|
||||
{
|
||||
if (size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.CreateFile(in pathNormalized, size, (CreateFileOptions)option);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result DeleteFile(in PathSf path)
|
||||
{
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.DeleteFile(in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CreateDirectory(in PathSf path)
|
||||
{
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (pathNormalized == RootDir)
|
||||
return ResultFs.PathAlreadyExists.Log();
|
||||
|
||||
rc = _baseFileSystem.Target.CreateDirectory(in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result DeleteDirectory(in PathSf path)
|
||||
{
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (pathNormalized == RootDir)
|
||||
return ResultFs.DirectoryNotDeletable.Log();
|
||||
|
||||
rc = _baseFileSystem.Target.DeleteDirectory(in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result DeleteDirectoryRecursively(in PathSf path)
|
||||
{
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (pathNormalized == RootDir)
|
||||
return ResultFs.DirectoryNotDeletable.Log();
|
||||
|
||||
rc = _baseFileSystem.Target.DeleteDirectoryRecursively(in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CleanDirectoryRecursively(in PathSf path)
|
||||
{
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.CleanDirectoryRecursively(in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result RenameFile(in PathSf currentPath, in PathSf newPath)
|
||||
{
|
||||
var currentPathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref currentPathNormalized, in currentPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var newPathNormalized = new Path();
|
||||
rc = SetUpPath(ref newPathNormalized, in newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.RenameFile(in currentPathNormalized, in newPathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
currentPathNormalized.Dispose();
|
||||
newPathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result RenameDirectory(in PathSf currentPath, in PathSf newPath)
|
||||
{
|
||||
var currentPathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref currentPathNormalized, in currentPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var newPathNormalized = new Path();
|
||||
rc = SetUpPath(ref newPathNormalized, in newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (PathUtility12.IsSubPath(currentPathNormalized.GetString(), newPathNormalized.GetString()))
|
||||
return ResultFs.DirectoryNotRenamable.Log();
|
||||
|
||||
rc = _baseFileSystem.Target.RenameDirectory(in currentPathNormalized, in newPathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
currentPathNormalized.Dispose();
|
||||
newPathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetEntryType(out uint entryType, in PathSf path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out entryType);
|
||||
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.GetEntryType(out DirectoryEntryType type, in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
entryType = (uint)type;
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetFreeSpaceSize(out long freeSpace, in PathSf path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out freeSpace);
|
||||
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.GetFreeSpaceSize(out long space, in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
freeSpace = space;
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetTotalSpaceSize(out long totalSpace, in PathSf path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out totalSpace);
|
||||
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.GetTotalSpaceSize(out long space, in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
totalSpace = space;
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenFile(out ReferenceCountedDisposable<IFileSf> file, in PathSf path, uint mode)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out file);
|
||||
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IFile fileInterface = null;
|
||||
try
|
||||
{
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseFileSystem.Target.OpenFile(out fileInterface, in pathNormalized, (OpenMode)mode);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
|
||||
var adapter = new FileInterfaceAdapter(Shared.Move(ref fileInterface), ref selfReference, _allowAllOperations);
|
||||
file = new ReferenceCountedDisposable<IFileSf>(adapter);
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fileInterface?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> directory, in PathSf path, uint mode)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
UnsafeHelpers.SkipParamInit(out directory);
|
||||
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
IDirectory dirInterface = null;
|
||||
try
|
||||
{
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = _baseFileSystem.Target.OpenDirectory(out dirInterface, in pathNormalized,
|
||||
(OpenDirectoryMode)mode);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
|
||||
var adapter = new DirectoryInterfaceAdapter(dirInterface, ref selfReference);
|
||||
directory = new ReferenceCountedDisposable<IDirectorySf>(adapter);
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
dirInterface?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result Commit()
|
||||
{
|
||||
return _baseFileSystem.Target.Commit();
|
||||
}
|
||||
|
||||
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in PathSf path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out timeStamp);
|
||||
|
||||
var pathNormalized = new Path();
|
||||
Result rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.GetFileTimeStampRaw(out FileTimeStampRaw tempTimeStamp, in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
timeStamp = tempTimeStamp;
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result QueryEntry(OutBuffer outBuffer, InBuffer inBuffer, int queryId, in PathSf path)
|
||||
{
|
||||
static Result PermissionCheck(QueryId queryId, FileSystemInterfaceAdapter fsAdapter)
|
||||
{
|
||||
if (queryId == QueryId.SetConcatenationFileAttribute ||
|
||||
queryId == QueryId.IsSignedSystemPartitionOnSdCardValid ||
|
||||
queryId == QueryId.QueryUnpreparedFileInformation)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (!fsAdapter._allowAllOperations)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
Result rc = PermissionCheck((QueryId)queryId, this);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var pathNormalized = new Path();
|
||||
rc = SetUpPath(ref pathNormalized, in path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = _baseFileSystem.Target.QueryEntry(outBuffer.Buffer, inBuffer.Buffer, (QueryId)queryId,
|
||||
in pathNormalized);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
pathNormalized.Dispose();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetImpl(out ReferenceCountedDisposable<IFileSystem> fileSystem)
|
||||
{
|
||||
fileSystem = _baseFileSystem.AddReference();
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Sf;
|
||||
using IFileSf = LibHac.FsSrv.Sf.IFile;
|
||||
using IDirectorySf = LibHac.FsSrv.Sf.IDirectory;
|
||||
|
||||
|
@ -13,8 +14,8 @@ namespace LibHac.FsSrv.Sf
|
|||
Result CreateDirectory(in Path path);
|
||||
Result DeleteDirectory(in Path path);
|
||||
Result DeleteDirectoryRecursively(in Path path);
|
||||
Result RenameFile(in Path oldPath, in Path newPath);
|
||||
Result RenameDirectory(in Path oldPath, in Path newPath);
|
||||
Result RenameFile(in Path currentPath, in Path newPath);
|
||||
Result RenameDirectory(in Path currentPath, in Path newPath);
|
||||
Result GetEntryType(out uint entryType, in Path path);
|
||||
Result OpenFile(out ReferenceCountedDisposable<IFileSf> file, in Path path, uint mode);
|
||||
Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> directory, in Path path, uint mode);
|
||||
|
@ -23,6 +24,6 @@ namespace LibHac.FsSrv.Sf
|
|||
Result GetTotalSpaceSize(out long totalSpace, in Path path);
|
||||
Result CleanDirectoryRecursively(in Path path);
|
||||
Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path);
|
||||
Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, int queryId, in Path path);
|
||||
Result QueryEntry(OutBuffer outBuffer, InBuffer inBuffer, int queryId, in Path path);
|
||||
}
|
||||
}
|
||||
|
|
51
src/LibHac/FsSystem/ThreadPriorityChanger.cs
Normal file
51
src/LibHac/FsSystem/ThreadPriorityChanger.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
|
||||
namespace LibHac.FsSystem
|
||||
{
|
||||
// Todo: Actually implement both of these structs
|
||||
public struct ScopedThreadPriorityChanger : IDisposable
|
||||
{
|
||||
public enum Mode
|
||||
{
|
||||
Absolute,
|
||||
Relative
|
||||
}
|
||||
|
||||
public ScopedThreadPriorityChanger(int priority, Mode mode)
|
||||
{
|
||||
// Change the current thread priority
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Change thread priority back
|
||||
}
|
||||
}
|
||||
|
||||
public struct ScopedThreadPriorityChangerByAccessPriority : IDisposable
|
||||
{
|
||||
public enum AccessMode
|
||||
{
|
||||
Read,
|
||||
Write
|
||||
}
|
||||
|
||||
private ScopedThreadPriorityChanger _scopedChanger;
|
||||
|
||||
public ScopedThreadPriorityChangerByAccessPriority(AccessMode mode)
|
||||
{
|
||||
_scopedChanger = new ScopedThreadPriorityChanger(GetThreadPriorityByAccessPriority(mode),
|
||||
ScopedThreadPriorityChanger.Mode.Absolute);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_scopedChanger.Dispose();
|
||||
}
|
||||
|
||||
private static int GetThreadPriorityByAccessPriority(AccessMode mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue