diff --git a/src/LibHac/Fs/Impl/DirectoryServiceObjectAdapter.cs b/src/LibHac/Fs/Impl/DirectoryServiceObjectAdapter.cs deleted file mode 100644 index e9312614..00000000 --- a/src/LibHac/Fs/Impl/DirectoryServiceObjectAdapter.cs +++ /dev/null @@ -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 -{ - /// - /// An adapter for using an service object as an . Used - /// when receiving a Horizon IPC directory object so it can be used as an locally. - /// - internal class DirectoryServiceObjectAdapter : IDirectory - { - private ReferenceCountedDisposable BaseDirectory { get; } - - public DirectoryServiceObjectAdapter(ReferenceCountedDisposable baseDirectory) - { - BaseDirectory = baseDirectory.AddReference(); - } - - protected override Result DoRead(out long entriesRead, Span entryBuffer) - { - Span buffer = MemoryMarshal.Cast(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); - } - } -} diff --git a/src/LibHac/Fs/Impl/FileServiceObjectAdapter.cs b/src/LibHac/Fs/Impl/FileServiceObjectAdapter.cs deleted file mode 100644 index 3781c2ae..00000000 --- a/src/LibHac/Fs/Impl/FileServiceObjectAdapter.cs +++ /dev/null @@ -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 -{ - /// - /// An adapter for using an service object as an . Used - /// when receiving a Horizon IPC file object so it can be used as an locally. - /// - internal class FileServiceObjectAdapter : IFile - { - private ReferenceCountedDisposable BaseFile { get; } - - public FileServiceObjectAdapter(ReferenceCountedDisposable baseFile) - { - BaseFile = baseFile.AddReference(); - } - - protected override Result DoRead(out long bytesRead, long offset, Span destination, in ReadOption option) - { - return BaseFile.Target.Read(out bytesRead, offset, new OutBuffer(destination), destination.Length, option); - } - - protected override Result DoWrite(long offset, ReadOnlySpan 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 outBuffer, OperationId operationId, long offset, long size, - ReadOnlySpan inBuffer) - { - switch (operationId) - { - case OperationId.InvalidateCache: - return BaseFile.Target.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size); - case OperationId.QueryRange: - if (outBuffer.Length != Unsafe.SizeOf()) - return ResultFs.InvalidSize.Log(); - - ref QueryRangeInfo info = ref SpanHelpers.AsStruct(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); - } - } -} \ No newline at end of file diff --git a/src/LibHac/Fs/Impl/FileSystemServiceObjectAdapter.cs b/src/LibHac/Fs/Shim/FileSystemServiceObjectAdapter.cs similarity index 56% rename from src/LibHac/Fs/Impl/FileSystemServiceObjectAdapter.cs rename to src/LibHac/Fs/Shim/FileSystemServiceObjectAdapter.cs index aeac867f..1286d837 100644 --- a/src/LibHac/Fs/Impl/FileSystemServiceObjectAdapter.cs +++ b/src/LibHac/Fs/Shim/FileSystemServiceObjectAdapter.cs @@ -1,28 +1,161 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using LibHac.Common; using LibHac.Fs.Fsa; +using LibHac.Sf; using LibHac.Util; -using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem; + +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 PathSf = LibHac.FsSrv.Sf.Path; +// ReSharper disable CheckNamespace namespace LibHac.Fs.Impl { /// - /// An adapter for using an service object as an . Used - /// when receiving a Horizon IPC file system object so it can be used as an locally. + /// An adapter for using an service object as an . Used + /// when receiving a Horizon IPC file object so it can be used as an locally. /// + /// Based on FS 12.0.3 (nnSdk 12.3.1) + internal class FileServiceObjectAdapter : IFile + { + private ReferenceCountedDisposable BaseFile { get; } + + public FileServiceObjectAdapter(ReferenceCountedDisposable 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 destination, in ReadOption option) + { + return BaseFile.Target.Read(out bytesRead, offset, new OutBuffer(destination), destination.Length, option); + } + + protected override Result DoWrite(long offset, ReadOnlySpan 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 outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer) + { + switch (operationId) + { + case OperationId.InvalidateCache: + return BaseFile.Target.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size); + case OperationId.QueryRange: + if (outBuffer.Length != Unsafe.SizeOf()) + return ResultFs.InvalidSize.Log(); + + ref QueryRangeInfo info = ref SpanHelpers.AsStruct(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); + } + } + } + + /// + /// An adapter for using an service object as an . Used + /// when receiving a Horizon IPC directory object so it can be used as an locally. + /// + /// Based on FS 12.0.3 (nnSdk 12.3.1) + internal class DirectoryServiceObjectAdapter : IDirectory + { + private ReferenceCountedDisposable BaseDirectory { get; } + + public DirectoryServiceObjectAdapter(ReferenceCountedDisposable 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 entryBuffer) + { + Span buffer = MemoryMarshal.Cast(entryBuffer); + return BaseDirectory.Target.Read(out entriesRead, new OutBuffer(buffer)); + } + + protected override Result DoGetEntryCount(out long entryCount) + { + return BaseDirectory.Target.GetEntryCount(out entryCount); + } + } + + /// + /// An adapter for using an service object as an . Used + /// when receiving a Horizon IPC file system object so it can be used as an locally. + /// + /// Based on FS 12.0.3 (nnSdk 12.3.1) internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget { private ReferenceCountedDisposable 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 baseFileSystem) { BaseFs = baseFileSystem.AddReference(); } + public override void Dispose() + { + BaseFs?.Dispose(); + base.Dispose(); + } + protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) { 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) { - Result rc = GetPathForServiceObject(out PathSf oldSfPath, currentPath); + Result rc = GetPathForServiceObject(out PathSf currentSfPath, currentPath); if (rc.IsFailure()) return rc; rc = GetPathForServiceObject(out PathSf newSfPath, newPath); 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) { - Result rc = GetPathForServiceObject(out PathSf oldSfPath, currentPath); + Result rc = GetPathForServiceObject(out PathSf currentSfPath, currentPath); if (rc.IsFailure()) return rc; rc = GetPathForServiceObject(out PathSf newSfPath, newPath); 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) @@ -190,38 +323,17 @@ namespace LibHac.Fs.Impl Result rc = GetPathForServiceObject(out PathSf sfPath, path); 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 GetMultiCommitTarget() + public ReferenceCountedDisposable GetFileSystem() { return BaseFs.AddReference(); } - public override void Dispose() + public ReferenceCountedDisposable GetMultiCommitTarget() { - BaseFs?.Dispose(); - 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 outPath = SpanHelpers.AsByteSpan(ref sfPath); - - // Copy and null terminate - StringUtils.Copy(outPath, path); - outPath[Unsafe.SizeOf() - 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); + return GetFileSystem(); } } } diff --git a/src/LibHac/FsSrv/Sf/IFile.cs b/src/LibHac/FsSrv/Sf/IFile.cs index 5236bf59..95d086df 100644 --- a/src/LibHac/FsSrv/Sf/IFile.cs +++ b/src/LibHac/FsSrv/Sf/IFile.cs @@ -12,5 +12,6 @@ namespace LibHac.FsSrv.Sf Result SetSize(long size); Result GetSize(out 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); } } \ No newline at end of file