Update FileSystemServiceObjectAdapter

This commit is contained in:
Alex Barney 2021-07-16 22:00:06 -07:00
parent 7d3ceb5315
commit 8e162cc3c8
4 changed files with 145 additions and 152 deletions

View file

@ -1,43 +0,0 @@
using System;
using System.Runtime.InteropServices;
using LibHac.Sf;
using IDirectory = LibHac.Fs.Fsa.IDirectory;
using IDirectorySf = LibHac.FsSrv.Sf.IDirectory;
namespace LibHac.Fs.Impl
{
/// <summary>
/// An adapter for using an <see cref="IDirectorySf"/> service object as an <see cref="IDirectory"/>. Used
/// when receiving a Horizon IPC directory object so it can be used as an <see cref="IDirectory"/> locally.
/// </summary>
internal class DirectoryServiceObjectAdapter : IDirectory
{
private ReferenceCountedDisposable<IDirectorySf> BaseDirectory { get; }
public DirectoryServiceObjectAdapter(ReferenceCountedDisposable<IDirectorySf> baseDirectory)
{
BaseDirectory = baseDirectory.AddReference();
}
protected override Result DoRead(out long entriesRead, Span<DirectoryEntry> entryBuffer)
{
Span<byte> buffer = MemoryMarshal.Cast<DirectoryEntry, byte>(entryBuffer);
return BaseDirectory.Target.Read(out entriesRead, new OutBuffer(buffer));
}
protected override Result DoGetEntryCount(out long entryCount)
{
return BaseDirectory.Target.GetEntryCount(out entryCount);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
BaseDirectory?.Dispose();
}
base.Dispose(disposing);
}
}
}

View file

@ -1,77 +0,0 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Sf;
using IFile = LibHac.Fs.Fsa.IFile;
using IFileSf = LibHac.FsSrv.Sf.IFile;
namespace LibHac.Fs.Impl
{
/// <summary>
/// An adapter for using an <see cref="IFileSf"/> service object as an <see cref="IFile"/>. Used
/// when receiving a Horizon IPC file object so it can be used as an <see cref="IFile"/> locally.
/// </summary>
internal class FileServiceObjectAdapter : IFile
{
private ReferenceCountedDisposable<IFileSf> BaseFile { get; }
public FileServiceObjectAdapter(ReferenceCountedDisposable<IFileSf> baseFile)
{
BaseFile = baseFile.AddReference();
}
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
{
return BaseFile.Target.Read(out bytesRead, offset, new OutBuffer(destination), destination.Length, option);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
{
return BaseFile.Target.Write(offset, new InBuffer(source), source.Length, option);
}
protected override Result DoFlush()
{
return BaseFile.Target.Flush();
}
protected override Result DoSetSize(long size)
{
return BaseFile.Target.SetSize(size);
}
protected override Result DoGetSize(out long size)
{
return BaseFile.Target.GetSize(out size);
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
ReadOnlySpan<byte> inBuffer)
{
switch (operationId)
{
case OperationId.InvalidateCache:
return BaseFile.Target.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size);
case OperationId.QueryRange:
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log();
ref QueryRangeInfo info = ref SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer);
return BaseFile.Target.OperateRange(out info, (int)OperationId.QueryRange, offset, size);
default:
return ResultFs.UnsupportedOperateRangeForFileServiceObjectAdapter.Log();
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
BaseFile?.Dispose();
}
base.Dispose(disposing);
}
}
}

View file

@ -1,28 +1,161 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.Sf;
using LibHac.Util; using LibHac.Util;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
using IFile = LibHac.Fs.Fsa.IFile;
using IFileSf = LibHac.FsSrv.Sf.IFile; using IFileSf = LibHac.FsSrv.Sf.IFile;
using IDirectory = LibHac.Fs.Fsa.IDirectory;
using IDirectorySf = LibHac.FsSrv.Sf.IDirectory; using IDirectorySf = LibHac.FsSrv.Sf.IDirectory;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
using PathSf = LibHac.FsSrv.Sf.Path; using PathSf = LibHac.FsSrv.Sf.Path;
// ReSharper disable CheckNamespace
namespace LibHac.Fs.Impl namespace LibHac.Fs.Impl
{ {
/// <summary> /// <summary>
/// An adapter for using an <see cref="IFileSystemSf"/> service object as an <see cref="Fsa.IFileSystem"/>. Used /// An adapter for using an <see cref="IFileSf"/> service object as an <see cref="IFile"/>. Used
/// when receiving a Horizon IPC file system object so it can be used as an <see cref="Fsa.IFileSystem"/> locally. /// when receiving a Horizon IPC file object so it can be used as an <see cref="IFile"/> locally.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
internal class FileServiceObjectAdapter : IFile
{
private ReferenceCountedDisposable<IFileSf> BaseFile { get; }
public FileServiceObjectAdapter(ReferenceCountedDisposable<IFileSf> baseFile)
{
BaseFile = baseFile.AddReference();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
BaseFile?.Dispose();
}
base.Dispose(disposing);
}
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
{
return BaseFile.Target.Read(out bytesRead, offset, new OutBuffer(destination), destination.Length, option);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
{
return BaseFile.Target.Write(offset, new InBuffer(source), source.Length, option);
}
protected override Result DoFlush()
{
return BaseFile.Target.Flush();
}
protected override Result DoSetSize(long size)
{
return BaseFile.Target.SetSize(size);
}
protected override Result DoGetSize(out long size)
{
return BaseFile.Target.GetSize(out size);
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
ReadOnlySpan<byte> inBuffer)
{
switch (operationId)
{
case OperationId.InvalidateCache:
return BaseFile.Target.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size);
case OperationId.QueryRange:
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log();
ref QueryRangeInfo info = ref SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer);
return BaseFile.Target.OperateRange(out info, (int)OperationId.QueryRange, offset, size);
default:
return BaseFile.Target.OperateRangeWithBuffer(new OutBuffer(outBuffer), new InBuffer(inBuffer),
(int)operationId, offset, size);
}
}
}
/// <summary>
/// An adapter for using an <see cref="IDirectorySf"/> service object as an <see cref="IDirectory"/>. Used
/// when receiving a Horizon IPC directory object so it can be used as an <see cref="IDirectory"/> locally.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
internal class DirectoryServiceObjectAdapter : IDirectory
{
private ReferenceCountedDisposable<IDirectorySf> BaseDirectory { get; }
public DirectoryServiceObjectAdapter(ReferenceCountedDisposable<IDirectorySf> baseDirectory)
{
BaseDirectory = baseDirectory.AddReference();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
BaseDirectory?.Dispose();
}
base.Dispose(disposing);
}
protected override Result DoRead(out long entriesRead, Span<DirectoryEntry> entryBuffer)
{
Span<byte> buffer = MemoryMarshal.Cast<DirectoryEntry, byte>(entryBuffer);
return BaseDirectory.Target.Read(out entriesRead, new OutBuffer(buffer));
}
protected override Result DoGetEntryCount(out long entryCount)
{
return BaseDirectory.Target.GetEntryCount(out entryCount);
}
}
/// <summary>
/// An adapter for using an <see cref="IFileSystemSf"/> service object as an <see cref="IFileSystem"/>. Used
/// when receiving a Horizon IPC file system object so it can be used as an <see cref="IFileSystem"/> locally.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget
{ {
private ReferenceCountedDisposable<IFileSystemSf> BaseFs { get; } private ReferenceCountedDisposable<IFileSystemSf> BaseFs { get; }
private static Result GetPathForServiceObject(out PathSf sfPath, in Path path)
{
UnsafeHelpers.SkipParamInit(out sfPath);
int length = StringUtils.Copy(SpanHelpers.AsByteSpan(ref sfPath), path.GetString(),
PathTool.EntryNameLengthMax + 1);
if (length > PathTool.EntryNameLengthMax)
return ResultFs.TooLongPath.Log();
return Result.Success;
}
public FileSystemServiceObjectAdapter(ReferenceCountedDisposable<IFileSystemSf> baseFileSystem) public FileSystemServiceObjectAdapter(ReferenceCountedDisposable<IFileSystemSf> baseFileSystem)
{ {
BaseFs = baseFileSystem.AddReference(); BaseFs = baseFileSystem.AddReference();
} }
public override void Dispose()
{
BaseFs?.Dispose();
base.Dispose();
}
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option)
{ {
Result rc = GetPathForServiceObject(out PathSf sfPath, path); Result rc = GetPathForServiceObject(out PathSf sfPath, path);
@ -73,24 +206,24 @@ namespace LibHac.Fs.Impl
protected override Result DoRenameFile(in Path currentPath, in Path newPath) protected override Result DoRenameFile(in Path currentPath, in Path newPath)
{ {
Result rc = GetPathForServiceObject(out PathSf oldSfPath, currentPath); Result rc = GetPathForServiceObject(out PathSf currentSfPath, currentPath);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
rc = GetPathForServiceObject(out PathSf newSfPath, newPath); rc = GetPathForServiceObject(out PathSf newSfPath, newPath);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
return BaseFs.Target.RenameFile(in oldSfPath, in newSfPath); return BaseFs.Target.RenameFile(in currentSfPath, in newSfPath);
} }
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath) protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
{ {
Result rc = GetPathForServiceObject(out PathSf oldSfPath, currentPath); Result rc = GetPathForServiceObject(out PathSf currentSfPath, currentPath);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
rc = GetPathForServiceObject(out PathSf newSfPath, newPath); rc = GetPathForServiceObject(out PathSf newSfPath, newPath);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
return BaseFs.Target.RenameDirectory(in oldSfPath, in newSfPath); return BaseFs.Target.RenameDirectory(in currentSfPath, in newSfPath);
} }
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path) protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
@ -190,38 +323,17 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, path); Result rc = GetPathForServiceObject(out PathSf sfPath, path);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
return BaseFs.Target.QueryEntry(outBuffer, inBuffer, (int)queryId, in sfPath); return BaseFs.Target.QueryEntry(new OutBuffer(outBuffer), new InBuffer(inBuffer), (int)queryId, in sfPath);
} }
public ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget() public ReferenceCountedDisposable<IFileSystemSf> GetFileSystem()
{ {
return BaseFs.AddReference(); return BaseFs.AddReference();
} }
public override void Dispose() public ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget()
{ {
BaseFs?.Dispose(); return GetFileSystem();
base.Dispose();
}
private Result GetPathForServiceObject(out PathSf sfPath, U8Span path)
{
// This is the function used to create Sf.Path structs. Get an unsafe byte span for init only.
UnsafeHelpers.SkipParamInit(out sfPath);
Span<byte> outPath = SpanHelpers.AsByteSpan(ref sfPath);
// Copy and null terminate
StringUtils.Copy(outPath, path);
outPath[Unsafe.SizeOf<PathSf>() - 1] = StringTraits.NullTerminator;
// Replace directory separators
PathUtility.Replace(outPath, StringTraits.AltDirectorySeparator, StringTraits.DirectorySeparator);
// Get lengths
int windowsSkipLength = WindowsPath.GetWindowsPathSkipLength(path);
var nonWindowsPath = new U8Span(sfPath.Str.Slice(windowsSkipLength));
int maxLength = PathTool.EntryNameLengthMax - windowsSkipLength;
return PathUtility.VerifyPath(null, nonWindowsPath, maxLength, maxLength);
} }
} }
} }

View file

@ -12,5 +12,6 @@ namespace LibHac.FsSrv.Sf
Result SetSize(long size); Result SetSize(long size);
Result GetSize(out long size); Result GetSize(out long size);
Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size); Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size);
Result OperateRangeWithBuffer(OutBuffer outBuffer, InBuffer inBuffer, int operationId, long offset, long size);
} }
} }