mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Add more FS IPC interfaces with adapters
This commit is contained in:
parent
5dc7c57851
commit
3837ed7eea
@ -106,6 +106,7 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
|
||||
2,3355,,AllocationFailureInSubdirectoryFileSystemA,In Initialize allocating RootPathBuffer
|
||||
2,3383,,AllocationFailureInAesXtsFileE,In Initialize
|
||||
2,3394,,AllocationFailureInEncryptedFileSystemCreatorA,In Create allocating AesXtsFileSystem
|
||||
2,3407,,AllocationFailureInFileSystemInterfaceAdapter, In OpenFile or OpenDirectory
|
||||
2,3420,,AllocationFailureInNew,
|
||||
2,3421,,AllocationFailureInCreateShared,
|
||||
2,3422,,AllocationFailureInMakeUnique,
|
||||
@ -238,7 +239,7 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
|
||||
|
||||
2,6030,6059,InvalidPathForOperation,
|
||||
2,6031,,DirectoryNotDeletable,
|
||||
2,6032,,DestinationIsSubPathOfSource,
|
||||
2,6032,,DirectoryNotRenamable,
|
||||
2,6033,,PathNotFoundInSaveDataFileTable,
|
||||
2,6034,,DifferentDestFileSystem,
|
||||
|
||||
@ -277,6 +278,7 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
|
||||
2,6350,,UnsupportedOperationInRoGameCardStorageWrite,
|
||||
2,6351,,UnsupportedOperationInRoGameCardStorageSetSize,
|
||||
2,6359,,UnsupportedOperationInConcatFsQueryEntry,
|
||||
2,6362,,UnsupportedOperationInFileServiceObjectAdapterA,Called OperateRange with an invalid operation ID.
|
||||
2,6364,,UnsupportedOperationModifyRomFsFileSystem,
|
||||
2,6365,,UnsupportedOperationInRomFsFileSystem,Called RomFsFileSystem::CommitProvisionally.
|
||||
2,6366,,UnsupportedOperationRomFsFileSystemGetSpace,
|
||||
|
Can't render this file because it has a wrong number of fields in line 220.
|
@ -1,9 +1,13 @@
|
||||
namespace LibHac.Fs
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
|
||||
public struct FileTimeStampRaw
|
||||
{
|
||||
public long Created;
|
||||
public long Accessed;
|
||||
public long Modified;
|
||||
public bool IsLocalTime;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
@ -167,7 +168,7 @@ namespace LibHac.Fs.Fsa
|
||||
/// <paramref name="oldPath"/> does not exist or is a file: <see cref="ResultFs.PathNotFound"/>
|
||||
/// <paramref name="newPath"/>'s parent directory does not exist: <see cref="ResultFs.PathNotFound"/>
|
||||
/// <paramref name="newPath"/> already exists as either a file or directory: <see cref="ResultFs.PathAlreadyExists"/>
|
||||
/// Either <paramref name="oldPath"/> or <paramref name="newPath"/> is a subpath of the other: <see cref="ResultFs.DestinationIsSubPathOfSource"/>
|
||||
/// Either <paramref name="oldPath"/> or <paramref name="newPath"/> is a subpath of the other: <see cref="ResultFs.DirectoryNotRenamable"/>
|
||||
/// </remarks>
|
||||
public Result RenameDirectory(U8Span oldPath, U8Span newPath)
|
||||
{
|
||||
@ -391,7 +392,7 @@ namespace LibHac.Fs.Fsa
|
||||
|
||||
protected virtual Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path)
|
||||
{
|
||||
timeStamp = default;
|
||||
Unsafe.SkipInit(out timeStamp);
|
||||
return ResultFs.NotImplemented.Log();
|
||||
}
|
||||
|
||||
|
9
src/LibHac/Fs/Fsa/IMultiCommitTarget.cs
Normal file
9
src/LibHac/Fs/Fsa/IMultiCommitTarget.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
namespace LibHac.Fs.Fsa
|
||||
{
|
||||
public interface IMultiCommitTarget
|
||||
{
|
||||
ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget();
|
||||
}
|
||||
}
|
42
src/LibHac/Fs/Impl/DirectoryServiceObjectAdapter.cs
Normal file
42
src/LibHac/Fs/Impl/DirectoryServiceObjectAdapter.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
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, 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);
|
||||
}
|
||||
}
|
||||
}
|
75
src/LibHac/Fs/Impl/FileServiceObjectAdapter.cs
Normal file
75
src/LibHac/Fs/Impl/FileServiceObjectAdapter.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
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, destination, option);
|
||||
}
|
||||
|
||||
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
|
||||
{
|
||||
return BaseFile.Target.Write(offset, source, 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.UnsupportedOperationInFileServiceObjectAdapterA.Log();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
BaseFile?.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
211
src/LibHac/Fs/Impl/FileSystemServiceObjectAdapter.cs
Normal file
211
src/LibHac/Fs/Impl/FileSystemServiceObjectAdapter.cs
Normal file
@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.Fs.Impl
|
||||
{
|
||||
/// <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>
|
||||
internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget
|
||||
{
|
||||
private ReferenceCountedDisposable<IFileSystemSf> BaseFs { get; }
|
||||
|
||||
public FileSystemServiceObjectAdapter(ReferenceCountedDisposable<IFileSystemSf> baseFileSystem)
|
||||
{
|
||||
BaseFs = baseFileSystem.AddReference();
|
||||
}
|
||||
|
||||
protected override Result DoCreateFile(U8Span path, long size, CreateFileOptions option)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.CreateFile(in sfPath, size, (int)option);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteFile(U8Span path)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.DeleteFile(in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoCreateDirectory(U8Span path)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.DeleteFile(in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectory(U8Span path)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.DeleteDirectory(in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectoryRecursively(U8Span path)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.DeleteDirectoryRecursively(in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoCleanDirectoryRecursively(U8Span path)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.CleanDirectoryRecursively(in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoRenameFile(U8Span oldPath, U8Span newPath)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path oldSfPath, oldPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = GetPathForServiceObject(out Path newSfPath, newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.RenameFile(in oldSfPath, in newSfPath);
|
||||
}
|
||||
|
||||
protected override Result DoRenameDirectory(U8Span oldPath, U8Span newPath)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path oldSfPath, oldPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = GetPathForServiceObject(out Path newSfPath, newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.RenameDirectory(in oldSfPath, in newSfPath);
|
||||
}
|
||||
|
||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, U8Span path)
|
||||
{
|
||||
Unsafe.SkipInit(out entryType);
|
||||
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ref uint sfEntryType = ref Unsafe.As<DirectoryEntryType, uint>(ref entryType);
|
||||
|
||||
return BaseFs.Target.GetEntryType(out sfEntryType, in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, U8Span path)
|
||||
{
|
||||
Unsafe.SkipInit(out freeSpace);
|
||||
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.GetFreeSpaceSize(out freeSpace, in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, U8Span path)
|
||||
{
|
||||
Unsafe.SkipInit(out totalSpace);
|
||||
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.GetTotalSpaceSize(out totalSpace, in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoOpenFile(out IFile file, U8Span path, OpenMode mode)
|
||||
{
|
||||
file = default;
|
||||
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = BaseFs.Target.OpenFile(out ReferenceCountedDisposable<IFileSf> sfFile, in sfPath, (uint)mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
file = new FileServiceObjectAdapter(sfFile);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoOpenDirectory(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
|
||||
{
|
||||
directory = default;
|
||||
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = BaseFs.Target.OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> sfDir, in sfPath, (uint)mode);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
directory = new DirectoryServiceObjectAdapter(sfDir);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoCommit()
|
||||
{
|
||||
return BaseFs.Target.Commit();
|
||||
}
|
||||
|
||||
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path)
|
||||
{
|
||||
Unsafe.SkipInit(out timeStamp);
|
||||
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.GetFileTimeStampRaw(out timeStamp, in sfPath);
|
||||
}
|
||||
|
||||
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, U8Span path)
|
||||
{
|
||||
Result rc = GetPathForServiceObject(out Path sfPath, path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return BaseFs.Target.QueryEntry(outBuffer, inBuffer, (int)queryId, in sfPath);
|
||||
}
|
||||
|
||||
public ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget()
|
||||
{
|
||||
return BaseFs;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
BaseFs?.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private Result GetPathForServiceObject(out Path sfPath, U8Span path)
|
||||
{
|
||||
// This is the function used to create Sf.Path structs. Get an unsafe byte span for init only.
|
||||
Unsafe.SkipInit(out sfPath);
|
||||
Span<byte> outPath = SpanHelpers.AsByteSpan(ref sfPath);
|
||||
|
||||
// Copy and null terminate
|
||||
StringUtils.Copy(outPath, path);
|
||||
outPath[Unsafe.SizeOf<Path>() - 1] = StringTraits.NullTerminator;
|
||||
|
||||
// Replace directory separators
|
||||
PathUtility.Replace(outPath, StringTraits.AltDirectorySeparator, StringTraits.DirectorySeparator);
|
||||
|
||||
// Get lengths
|
||||
int windowsSkipLength = PathUtility.GetWindowsPathSkipLength(path);
|
||||
var nonWindowsPath = new U8Span(sfPath.Str.Slice(windowsSkipLength));
|
||||
int maxLength = PathTool.EntryNameLengthMax - windowsSkipLength;
|
||||
return PathUtility.VerifyPath(nonWindowsPath, maxLength, maxLength);
|
||||
}
|
||||
}
|
||||
}
|
53
src/LibHac/Fs/Impl/ReaderWriterLockHandlers.cs
Normal file
53
src/LibHac/Fs/Impl/ReaderWriterLockHandlers.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace LibHac.Fs.Impl
|
||||
{
|
||||
/// <summary>
|
||||
/// A wrapper for handling write access to a reader-writer lock.
|
||||
/// </summary>
|
||||
public class UniqueLock : IDisposable
|
||||
{
|
||||
private ReaderWriterLockSlim _lock;
|
||||
private bool _hasLock;
|
||||
|
||||
public UniqueLock(ReaderWriterLockSlim readerWriterLock)
|
||||
{
|
||||
_lock = readerWriterLock;
|
||||
readerWriterLock.EnterWriteLock();
|
||||
_hasLock = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_hasLock)
|
||||
{
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A wrapper for handling read access to a reader-writer lock.
|
||||
/// </summary>
|
||||
public class SharedLock : IDisposable
|
||||
{
|
||||
private ReaderWriterLockSlim _lock;
|
||||
private bool _hasLock;
|
||||
|
||||
public SharedLock(ReaderWriterLockSlim readerWriterLock)
|
||||
{
|
||||
_lock = readerWriterLock;
|
||||
readerWriterLock.EnterReadLock();
|
||||
_hasLock = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_hasLock)
|
||||
{
|
||||
_lock.EnterReadLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
73
src/LibHac/Fs/Impl/StorageServiceObjectAdapter.cs
Normal file
73
src/LibHac/Fs/Impl/StorageServiceObjectAdapter.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
namespace LibHac.Fs.Impl
|
||||
{
|
||||
/// <summary>
|
||||
/// An adapter for using an <see cref="IStorageSf"/> service object as an <see cref="IStorage"/>. Used
|
||||
/// when receiving a Horizon IPC storage object so it can be used as an <see cref="IStorage"/> locally.
|
||||
/// </summary>
|
||||
internal class StorageServiceObjectAdapter : IStorage
|
||||
{
|
||||
private ReferenceCountedDisposable<IStorageSf> BaseStorage { get; }
|
||||
|
||||
public StorageServiceObjectAdapter(ReferenceCountedDisposable<IStorageSf> baseStorage)
|
||||
{
|
||||
BaseStorage = baseStorage.AddReference();
|
||||
}
|
||||
protected override Result DoRead(long offset, Span<byte> destination)
|
||||
{
|
||||
return BaseStorage.Target.Read(offset, destination);
|
||||
}
|
||||
|
||||
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
|
||||
{
|
||||
return BaseStorage.Target.Write(offset, source);
|
||||
}
|
||||
|
||||
protected override Result DoFlush()
|
||||
{
|
||||
return BaseStorage.Target.Flush();
|
||||
}
|
||||
|
||||
protected override Result DoSetSize(long size)
|
||||
{
|
||||
return BaseStorage.Target.SetSize(size);
|
||||
}
|
||||
|
||||
protected override Result DoGetSize(out long size)
|
||||
{
|
||||
return BaseStorage.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 BaseStorage.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 BaseStorage.Target.OperateRange(out info, (int)OperationId.QueryRange, offset, size);
|
||||
default:
|
||||
return ResultFs.UnsupportedOperationInFileServiceObjectAdapterA.Log();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
BaseStorage?.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ namespace LibHac.Fs
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsWindowsDriveCharacter(byte c)
|
||||
{
|
||||
// Mask lowercase letters to uppercase and check if it's in range
|
||||
return (0b1101_1111 & c) - 'A' <= 'Z' - 'A';
|
||||
//return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z';
|
||||
}
|
||||
|
@ -1,11 +1,31 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x40)]
|
||||
public struct QueryRangeInfo
|
||||
{
|
||||
public uint AesCtrKeyType;
|
||||
public uint SpeedEmulationType;
|
||||
public int AesCtrKeyType;
|
||||
public int SpeedEmulationType;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
this = default;
|
||||
}
|
||||
|
||||
public void Merge(in QueryRangeInfo other)
|
||||
{
|
||||
AesCtrKeyType |= other.AesCtrKeyType;
|
||||
SpeedEmulationType |= other.SpeedEmulationType;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum AesCtrKeyTypeFlag
|
||||
{
|
||||
InternalKeyForSoftwareAes = 1 << 0,
|
||||
InternalKeyForHardwareAes = 1 << 1,
|
||||
ExternalKeyForHardwareAes = 1 << 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +130,8 @@ namespace LibHac.Fs
|
||||
public static Result.Base AllocationFailureInAesXtsFileE => new Result.Base(ModuleFs, 3383);
|
||||
/// <summary>In Create allocating AesXtsFileSystem<br/>Error code: 2002-3394; Inner value: 0x1a8402</summary>
|
||||
public static Result.Base AllocationFailureInEncryptedFileSystemCreatorA => new Result.Base(ModuleFs, 3394);
|
||||
/// <summary> In OpenFile or OpenDirectory<br/>Error code: 2002-3407; Inner value: 0x1a9e02</summary>
|
||||
public static Result.Base AllocationFailureInFileSystemInterfaceAdapter => new Result.Base(ModuleFs, 3407);
|
||||
/// <summary>Error code: 2002-3420; Inner value: 0x1ab802</summary>
|
||||
public static Result.Base AllocationFailureInNew => new Result.Base(ModuleFs, 3420);
|
||||
/// <summary>Error code: 2002-3421; Inner value: 0x1aba02</summary>
|
||||
@ -370,7 +372,7 @@ namespace LibHac.Fs
|
||||
/// <summary>Error code: 2002-6031; Inner value: 0x2f1e02</summary>
|
||||
public static Result.Base DirectoryNotDeletable => new Result.Base(ModuleFs, 6031);
|
||||
/// <summary>Error code: 2002-6032; Inner value: 0x2f2002</summary>
|
||||
public static Result.Base DestinationIsSubPathOfSource => new Result.Base(ModuleFs, 6032);
|
||||
public static Result.Base DirectoryNotRenamable => new Result.Base(ModuleFs, 6032);
|
||||
/// <summary>Error code: 2002-6033; Inner value: 0x2f2202</summary>
|
||||
public static Result.Base PathNotFoundInSaveDataFileTable => new Result.Base(ModuleFs, 6033);
|
||||
/// <summary>Error code: 2002-6034; Inner value: 0x2f2402</summary>
|
||||
@ -443,6 +445,8 @@ namespace LibHac.Fs
|
||||
public static Result.Base UnsupportedOperationInRoGameCardStorageSetSize => new Result.Base(ModuleFs, 6351);
|
||||
/// <summary>Error code: 2002-6359; Inner value: 0x31ae02</summary>
|
||||
public static Result.Base UnsupportedOperationInConcatFsQueryEntry => new Result.Base(ModuleFs, 6359);
|
||||
/// <summary>Called OperateRange with an invalid operation ID.<br/>Error code: 2002-6362; Inner value: 0x31b402</summary>
|
||||
public static Result.Base UnsupportedOperationInFileServiceObjectAdapterA => new Result.Base(ModuleFs, 6362);
|
||||
/// <summary>Error code: 2002-6364; Inner value: 0x31b802</summary>
|
||||
public static Result.Base UnsupportedOperationModifyRomFsFileSystem => new Result.Base(ModuleFs, 6364);
|
||||
/// <summary>Called RomFsFileSystem::CommitProvisionally.<br/>Error code: 2002-6365; Inner value: 0x31ba02</summary>
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
@ -44,11 +44,16 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
rc = fsProxy.OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystem> fileSystem, in sfPath,
|
||||
rc = fsProxy.OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in sfPath,
|
||||
default, FileSystemProxyType.Package);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return fs.Register(mountName, fileSystem.Target);
|
||||
using (fileSystem)
|
||||
{
|
||||
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
|
||||
|
||||
return fs.Register(mountName, fileSystemAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.FsSystem;
|
||||
@ -91,13 +91,17 @@ namespace LibHac.Fs.Shim
|
||||
// Nintendo doesn't use the provided rootPath
|
||||
FspPath.CreateEmpty(out FspPath sfPath);
|
||||
|
||||
rc = fsProxy.OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, in sfPath,
|
||||
rc = fsProxy.OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in sfPath,
|
||||
partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var nameGenerator = new BisCommonMountNameGenerator(partitionId);
|
||||
using (fileSystem)
|
||||
{
|
||||
var nameGenerator = new BisCommonMountNameGenerator(partitionId);
|
||||
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
|
||||
|
||||
return fs.Register(mountName, fileSystem.Target, nameGenerator);
|
||||
return fs.Register(mountName, fileSystemAdapter, nameGenerator);
|
||||
}
|
||||
}
|
||||
|
||||
public static U8Span GetBisMountName(BisPartitionId partitionId)
|
||||
@ -165,11 +169,16 @@ namespace LibHac.Fs.Shim
|
||||
partitionStorage = default;
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
Result rc = fsProxy.OpenBisStorage(out IStorage storage, partitionId);
|
||||
Result rc = fsProxy.OpenBisStorage(out ReferenceCountedDisposable<IStorageSf> storage, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
partitionStorage = storage;
|
||||
return Result.Success;
|
||||
using (storage)
|
||||
{
|
||||
var storageAdapter = new StorageServiceObjectAdapter(storage);
|
||||
|
||||
partitionStorage = storageAdapter;
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public static Result InvalidateBisCache(this FileSystemClient fs)
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Ncm;
|
||||
|
||||
@ -49,11 +49,16 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
IFileSystemProxyForLoader fsProxy = fs.GetFileSystemProxyForLoaderServiceObject();
|
||||
|
||||
rc = fsProxy.OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystem> codeFs, out verificationData,
|
||||
rc = fsProxy.OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystemSf> codeFs, out verificationData,
|
||||
in fsPath, programId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return fs.Register(mountName, codeFs.Target);
|
||||
using (codeFs)
|
||||
{
|
||||
var fileSystemAdapter = new FileSystemServiceObjectAdapter(codeFs);
|
||||
|
||||
return fs.Register(mountName, fileSystemAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Ncm;
|
||||
@ -27,11 +27,16 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
rc = fsProxy.OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystem> fileSystem, programId,
|
||||
rc = fsProxy.OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, programId,
|
||||
fspType);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return fs.Register(mountName, fileSystem.Target);
|
||||
using (fileSystem)
|
||||
{
|
||||
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
|
||||
|
||||
return fs.Register(mountName, fileSystemAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
public static Result MountContent(this FileSystemClient fs, U8Span mountName, U8Span path, ProgramId programId, ContentType type)
|
||||
@ -60,11 +65,16 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
Result rc = fsProxy.OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystem> fileSystem, in fsPath,
|
||||
Result rc = fsProxy.OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in fsPath,
|
||||
id, type);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return fs.Register(mountName, fileSystem.Target);
|
||||
using (fileSystem)
|
||||
{
|
||||
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
|
||||
|
||||
return fs.Register(mountName, fileSystemAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
private static FileSystemProxyType ConvertToFileSystemProxyType(ContentType type) => type switch
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.Fs.Shim
|
||||
@ -20,12 +21,17 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
rc = fsProxy.OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> contentFs, storageId);
|
||||
rc = fsProxy.OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> contentFs, storageId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var mountNameGenerator = new ContentStorageCommonMountNameGenerator(storageId);
|
||||
using (contentFs)
|
||||
{
|
||||
var mountNameGenerator = new ContentStorageCommonMountNameGenerator(storageId);
|
||||
|
||||
return fs.Register(mountName, contentFs.Target, mountNameGenerator);
|
||||
var fileSystemAdapter = new FileSystemServiceObjectAdapter(contentFs);
|
||||
|
||||
return fs.Register(mountName, fileSystemAdapter, mountNameGenerator);
|
||||
}
|
||||
}
|
||||
|
||||
public static U8String GetContentStorageMountName(ContentStorageId storageId)
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
namespace LibHac.Fs.Shim
|
||||
{
|
||||
@ -48,12 +49,16 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
rc = fsProxy.OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystem> cardFs, handle, partitionId);
|
||||
rc = fsProxy.OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> cardFs, handle, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var mountNameGenerator = new GameCardCommonMountNameGenerator(handle, partitionId);
|
||||
using (cardFs)
|
||||
{
|
||||
var mountNameGenerator = new GameCardCommonMountNameGenerator(handle, partitionId);
|
||||
var fileSystemAdapter = new FileSystemServiceObjectAdapter(cardFs);
|
||||
|
||||
return fs.Register(mountName, cardFs.Target, mountNameGenerator);
|
||||
return fs.Register(mountName, fileSystemAdapter, mountNameGenerator);
|
||||
}
|
||||
}
|
||||
|
||||
private class GameCardCommonMountNameGenerator : ICommonMountNameGenerator
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
namespace LibHac.Fs.Shim
|
||||
{
|
||||
@ -41,10 +42,15 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||
|
||||
rc = fsProxy.OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem);
|
||||
rc = fsProxy.OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return fs.Register(mountName, fileSystem.Target);
|
||||
using (fileSystem)
|
||||
{
|
||||
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
|
||||
|
||||
return fs.Register(mountName, fileSystemAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ namespace LibHac.FsSrv
|
||||
_processId = processId;
|
||||
}
|
||||
|
||||
public Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, in FspPath rootPath,
|
||||
public Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath rootPath,
|
||||
BisPartitionId partitionId)
|
||||
{
|
||||
fileSystem = default;
|
||||
@ -50,12 +50,24 @@ namespace LibHac.FsSrv
|
||||
var normalizer = new PathNormalizer(rootPath, PathNormalizer.Option.AcceptEmpty);
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
rc = _serviceImpl.OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystem> bisFs, normalizer.Path,
|
||||
partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
ReferenceCountedDisposable<IFileSystem> fs = null;
|
||||
|
||||
fileSystem = bisFs;
|
||||
return Result.Success;
|
||||
try
|
||||
{
|
||||
// Open the file system
|
||||
rc = _serviceImpl.OpenBisFileSystem(out fs, normalizer.Path,
|
||||
partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Create an SF adapter for the file system
|
||||
fileSystem = FileSystemInterfaceAdapter.CreateSharedSfFileSystem(ref fs);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result CreatePaddingFile(long size)
|
||||
@ -86,7 +98,7 @@ namespace LibHac.FsSrv
|
||||
return _serviceImpl.DeleteAllPaddingFiles();
|
||||
}
|
||||
|
||||
public Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, GameCardHandle handle,
|
||||
public Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, GameCardHandle handle,
|
||||
GameCardPartition partitionId)
|
||||
{
|
||||
fileSystem = default;
|
||||
@ -97,14 +109,25 @@ namespace LibHac.FsSrv
|
||||
if (!programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountGameCard).CanRead)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
rc = _serviceImpl.OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystem> gcFs, handle, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
ReferenceCountedDisposable<IFileSystem> fs = null;
|
||||
|
||||
fileSystem = gcFs;
|
||||
return Result.Success;
|
||||
try
|
||||
{
|
||||
rc = _serviceImpl.OpenGameCardFileSystem(out fs, handle, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Create an SF adapter for the file system
|
||||
fileSystem = FileSystemInterfaceAdapter.CreateSharedSfFileSystem(ref fs);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem)
|
||||
public Result OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
|
||||
{
|
||||
fileSystem = default;
|
||||
|
||||
@ -116,11 +139,22 @@ namespace LibHac.FsSrv
|
||||
if (!accessibility.CanRead || !accessibility.CanWrite)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
rc = _serviceImpl.OpenSdCardProxyFileSystem(out ReferenceCountedDisposable<IFileSystem> sdCardFs);
|
||||
if (rc.IsFailure()) return rc;
|
||||
ReferenceCountedDisposable<IFileSystem> fs = null;
|
||||
|
||||
fileSystem = sdCardFs;
|
||||
return Result.Success;
|
||||
try
|
||||
{
|
||||
rc = _serviceImpl.OpenSdCardProxyFileSystem(out fs);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Create an SF adapter for the file system
|
||||
fileSystem = FileSystemInterfaceAdapter.CreateSharedSfFileSystem(ref fs);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result FormatSdCardFileSystem()
|
||||
@ -150,7 +184,7 @@ namespace LibHac.FsSrv
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
ImageDirectoryId directoryId)
|
||||
{
|
||||
fileSystem = default;
|
||||
@ -178,15 +212,25 @@ namespace LibHac.FsSrv
|
||||
default:
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
}
|
||||
ReferenceCountedDisposable<IFileSystem> fs = null;
|
||||
|
||||
rc = _serviceImpl.OpenBaseFileSystem(out ReferenceCountedDisposable<IFileSystem> imageFs, id);
|
||||
if (rc.IsFailure()) return rc;
|
||||
try
|
||||
{
|
||||
rc = _serviceImpl.OpenBaseFileSystem(out fs, id);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fileSystem = imageFs;
|
||||
return Result.Success;
|
||||
// Create an SF adapter for the file system
|
||||
fileSystem = FileSystemInterfaceAdapter.CreateSharedSfFileSystem(ref fs);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result OpenBisWiper(out IWiper bisWiper, NativeHandle transferMemoryHandle, ulong transferMemorySize)
|
||||
public Result OpenBisWiper(out ReferenceCountedDisposable<IWiper> bisWiper, NativeHandle transferMemoryHandle, ulong transferMemorySize)
|
||||
{
|
||||
bisWiper = default;
|
||||
|
||||
@ -200,7 +244,7 @@ namespace LibHac.FsSrv
|
||||
rc = _serviceImpl.OpenBisWiper(out IWiper wiper, transferMemoryHandle, transferMemorySize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
bisWiper = wiper;
|
||||
bisWiper = new ReferenceCountedDisposable<IWiper>(wiper);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ namespace LibHac.FsSrv
|
||||
private FileSystemCreators FsCreators => Config.FsCreatorInterfaces;
|
||||
internal ProgramRegistryImpl ProgramRegistry { get; }
|
||||
|
||||
private ExternalKeySet ExternalKeys { get; }
|
||||
private IDeviceOperator DeviceOperator { get; }
|
||||
|
||||
private byte[] SdEncryptionSeed { get; } = new byte[0x10];
|
||||
@ -26,11 +25,10 @@ namespace LibHac.FsSrv
|
||||
|
||||
internal ISaveDataIndexerManager SaveDataIndexerManager { get; private set; }
|
||||
|
||||
public FileSystemProxyCoreImpl(FileSystemProxyConfiguration config, ExternalKeySet externalKeys, IDeviceOperator deviceOperator)
|
||||
public FileSystemProxyCoreImpl(FileSystemProxyConfiguration config, IDeviceOperator deviceOperator)
|
||||
{
|
||||
Config = config;
|
||||
ProgramRegistry = new ProgramRegistryImpl(Config.ProgramRegistryService);
|
||||
ExternalKeys = externalKeys ?? new ExternalKeySet();
|
||||
DeviceOperator = deviceOperator;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ namespace LibHac.FsSrv
|
||||
public class FileSystemProxyImpl : IFileSystemProxy, IFileSystemProxyForLoader
|
||||
{
|
||||
private FileSystemProxyCoreImpl FsProxyCore { get; }
|
||||
private ReferenceCountedDisposable<NcaFileSystemService> NcaFileSystemService { get; set; }
|
||||
private ReferenceCountedDisposable<NcaFileSystemService> NcaFsService { get; set; }
|
||||
internal HorizonClient Hos { get; }
|
||||
|
||||
public ulong CurrentProcess { get; private set; }
|
||||
@ -44,7 +44,7 @@ namespace LibHac.FsSrv
|
||||
return new ProgramRegistryService(FsProxyCore.Config.ProgramRegistryService, CurrentProcess);
|
||||
}
|
||||
|
||||
public Result OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystem> fileSystem, in FspPath path,
|
||||
public Result OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath path,
|
||||
ulong id, FileSystemProxyType fsType)
|
||||
{
|
||||
|
||||
@ -58,7 +58,7 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenFileSystemWithId(out fileSystem, in path, id, fsType);
|
||||
}
|
||||
|
||||
public Result OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
ProgramId programId, FileSystemProxyType fsType)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
@ -71,7 +71,7 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenFileSystemWithPatch(out fileSystem, programId, fsType);
|
||||
}
|
||||
|
||||
public Result OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
out CodeVerificationData verificationData, in FspPath path, ProgramId programId)
|
||||
{
|
||||
Unsafe.SkipInit(out verificationData);
|
||||
@ -101,9 +101,7 @@ namespace LibHac.FsSrv
|
||||
CurrentProcess = processId;
|
||||
|
||||
// Initialize the NCA file system service
|
||||
var ncaService = new NcaFileSystemService(FsProxyCore.Config.NcaFileSystemService, processId);
|
||||
NcaFileSystemService = new ReferenceCountedDisposable<NcaFileSystemService>(ncaService);
|
||||
NcaFileSystemService.Target.SetSelfReference(NcaFileSystemService);
|
||||
NcaFsService = NcaFileSystemService.Create(FsProxyCore.Config.NcaFileSystemService, processId);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
@ -113,7 +111,7 @@ namespace LibHac.FsSrv
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenDataFileSystemByCurrentProcess(out ReferenceCountedDisposable<IFileSystem> fileSystem)
|
||||
public Result OpenDataFileSystemByCurrentProcess(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
if (rc.IsFailure())
|
||||
@ -125,7 +123,7 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenDataFileSystemByCurrentProcess(out fileSystem);
|
||||
}
|
||||
|
||||
public Result OpenDataFileSystemByProgramId(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenDataFileSystemByProgramId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
ProgramId programId)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
@ -138,7 +136,7 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenDataFileSystemByProgramId(out fileSystem, programId);
|
||||
}
|
||||
|
||||
public Result OpenDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorage> storage)
|
||||
public Result OpenDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorageSf> storage)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
if (rc.IsFailure())
|
||||
@ -150,7 +148,7 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenDataStorageByCurrentProcess(out storage);
|
||||
}
|
||||
|
||||
public Result OpenDataStorageByProgramId(out ReferenceCountedDisposable<IStorage> storage, ProgramId programId)
|
||||
public Result OpenDataStorageByProgramId(out ReferenceCountedDisposable<IStorageSf> storage, ProgramId programId)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
if (rc.IsFailure())
|
||||
@ -162,7 +160,7 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenDataStorageByProgramId(out storage, programId);
|
||||
}
|
||||
|
||||
public Result OpenDataStorageByDataId(out ReferenceCountedDisposable<IStorage> storage, DataId dataId, StorageId storageId)
|
||||
public Result OpenDataStorageByDataId(out ReferenceCountedDisposable<IStorageSf> storage, DataId dataId, StorageId storageId)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
if (rc.IsFailure())
|
||||
@ -174,13 +172,13 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenDataStorageByDataId(out storage, dataId, storageId);
|
||||
}
|
||||
|
||||
public Result OpenPatchDataStorageByCurrentProcess(out IStorage storage)
|
||||
public Result OpenPatchDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorageSf> storage)
|
||||
{
|
||||
storage = default;
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
|
||||
public Result OpenDataFileSystemWithProgramIndex(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenDataFileSystemWithProgramIndex(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
byte programIndex)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
@ -193,7 +191,7 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenDataFileSystemWithProgramIndex(out fileSystem, programIndex);
|
||||
}
|
||||
|
||||
public Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable<IStorage> storage, byte programIndex)
|
||||
public Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable<IStorageSf> storage, byte programIndex)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
if (rc.IsFailure())
|
||||
@ -744,7 +742,7 @@ namespace LibHac.FsSrv
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
ImageDirectoryId directoryId)
|
||||
{
|
||||
return GetBaseFileSystemService().OpenImageDirectoryFileSystem(out fileSystem, directoryId);
|
||||
@ -760,13 +758,13 @@ namespace LibHac.FsSrv
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, in FspPath rootPath,
|
||||
public Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath rootPath,
|
||||
BisPartitionId partitionId)
|
||||
{
|
||||
return GetBaseFileSystemService().OpenBisFileSystem(out fileSystem, in rootPath, partitionId);
|
||||
}
|
||||
|
||||
public Result OpenBisStorage(out IStorage storage, BisPartitionId partitionId)
|
||||
public Result OpenBisStorage(out ReferenceCountedDisposable<IStorageSf> storage, BisPartitionId partitionId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@ -788,7 +786,7 @@ namespace LibHac.FsSrv
|
||||
return OpenHostFileSystemWithOption(out fileSystem, ref path, MountHostOption.None);
|
||||
}
|
||||
|
||||
public Result OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem)
|
||||
public Result OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
|
||||
{
|
||||
return GetBaseFileSystemService().OpenSdCardFileSystem(out fileSystem);
|
||||
}
|
||||
@ -952,7 +950,8 @@ namespace LibHac.FsSrv
|
||||
}
|
||||
}
|
||||
|
||||
public Result OpenSaveDataInternalStorageFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
public Result OpenSaveDataInternalStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@ -1062,7 +1061,7 @@ namespace LibHac.FsSrv
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, ContentStorageId storageId)
|
||||
public Result OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, ContentStorageId storageId)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
if (rc.IsFailure())
|
||||
@ -1074,7 +1073,8 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.OpenContentStorageFileSystem(out fileSystem, storageId);
|
||||
}
|
||||
|
||||
public Result OpenCloudBackupWorkStorageFileSystem(out IFileSystem fileSystem, CloudBackupWorkStorageId storageId)
|
||||
public Result OpenCloudBackupWorkStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
CloudBackupWorkStorageId storageId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@ -1086,7 +1086,7 @@ namespace LibHac.FsSrv
|
||||
return FsProxyCore.OpenCustomStorageFileSystem(out fileSystem, storageId);
|
||||
}
|
||||
|
||||
public Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
GameCardHandle handle, GameCardPartition partitionId)
|
||||
{
|
||||
return GetBaseFileSystemService().OpenGameCardFileSystem(out fileSystem, handle, partitionId);
|
||||
@ -1245,7 +1245,7 @@ namespace LibHac.FsSrv
|
||||
return ncaFsService.RegisterUpdatePartition();
|
||||
}
|
||||
|
||||
public Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystem> fileSystem)
|
||||
public Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
|
||||
{
|
||||
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
|
||||
if (rc.IsFailure())
|
||||
@ -1296,7 +1296,8 @@ namespace LibHac.FsSrv
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenBisWiper(out IWiper bisWiper, NativeHandle transferMemoryHandle, ulong transferMemorySize)
|
||||
public Result OpenBisWiper(out ReferenceCountedDisposable<IWiper> bisWiper, NativeHandle transferMemoryHandle,
|
||||
ulong transferMemorySize)
|
||||
{
|
||||
return GetBaseFileSystemService().OpenBisWiper(out bisWiper, transferMemoryHandle, transferMemorySize);
|
||||
}
|
||||
@ -1357,13 +1358,13 @@ namespace LibHac.FsSrv
|
||||
|
||||
private Result GetNcaFileSystemService(out NcaFileSystemService ncaFsService)
|
||||
{
|
||||
if (NcaFileSystemService is null)
|
||||
if (NcaFsService is null)
|
||||
{
|
||||
ncaFsService = null;
|
||||
return ResultFs.PreconditionViolation.Log();
|
||||
}
|
||||
|
||||
ncaFsService = NcaFileSystemService.Target;
|
||||
ncaFsService = NcaFsService.Target;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -40,12 +40,11 @@ namespace LibHac.FsSrv
|
||||
|
||||
IsDebugMode = false;
|
||||
|
||||
ExternalKeySet externalKeySet = config.ExternalKeySet ?? new ExternalKeySet();
|
||||
Timer = config.TimeSpanGenerator ?? new StopWatchTimeSpanGenerator();
|
||||
|
||||
FileSystemProxyConfiguration fspConfig = InitializeFileSystemProxyConfiguration(config);
|
||||
|
||||
FsProxyCore = new FileSystemProxyCoreImpl(fspConfig, externalKeySet, config.DeviceOperator);
|
||||
FsProxyCore = new FileSystemProxyCoreImpl(fspConfig, config.DeviceOperator);
|
||||
|
||||
FsProxyCore.SetSaveDataIndexerManager(new SaveDataIndexerManager(Hos.Fs, SaveIndexerId,
|
||||
new ArrayPoolMemoryResource(), new SdHandleManager(), false));
|
||||
|
@ -13,16 +13,16 @@ namespace LibHac.FsSrv
|
||||
public interface IFileSystemProxy
|
||||
{
|
||||
Result SetCurrentProcess(ulong processId);
|
||||
Result OpenDataFileSystemByCurrentProcess(out ReferenceCountedDisposable<IFileSystem> fileSystem);
|
||||
Result OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystem> fileSystem, ProgramId programId, FileSystemProxyType fsType);
|
||||
Result OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystem> fileSystem, in FspPath path, ulong id, FileSystemProxyType fsType);
|
||||
Result OpenDataFileSystemByProgramId(out ReferenceCountedDisposable<IFileSystem> fileSystem, ProgramId programId);
|
||||
Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, in FspPath rootPath, BisPartitionId partitionId);
|
||||
Result OpenBisStorage(out IStorage storage, BisPartitionId partitionId);
|
||||
Result OpenDataFileSystemByCurrentProcess(out ReferenceCountedDisposable<IFileSystemSf> fileSystem);
|
||||
Result OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, ProgramId programId, FileSystemProxyType fsType);
|
||||
Result OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath path, ulong id, FileSystemProxyType fsType);
|
||||
Result OpenDataFileSystemByProgramId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, ProgramId programId);
|
||||
Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath rootPath, BisPartitionId partitionId);
|
||||
Result OpenBisStorage(out ReferenceCountedDisposable<IStorageSf> storage, BisPartitionId partitionId);
|
||||
Result InvalidateBisCache();
|
||||
Result OpenHostFileSystemWithOption(out IFileSystem fileSystem, ref FsPath path, MountHostOption option);
|
||||
Result OpenHostFileSystem(out IFileSystem fileSystem, ref FsPath path);
|
||||
Result OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem);
|
||||
Result OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem);
|
||||
Result FormatSdCardFileSystem();
|
||||
Result DeleteSaveDataFileSystem(ulong saveDataId);
|
||||
Result CreateSaveDataFileSystem(ref SaveDataAttribute attribute, ref SaveDataCreationInfo creationInfo, ref SaveMetaCreateInfo metaCreateInfo);
|
||||
@ -33,7 +33,7 @@ namespace LibHac.FsSrv
|
||||
Result IsExFatSupported(out bool isSupported);
|
||||
Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, ref SaveDataAttribute attribute);
|
||||
Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId);
|
||||
Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, GameCardHandle handle, GameCardPartition partitionId);
|
||||
Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, GameCardHandle handle, GameCardPartition partitionId);
|
||||
Result ExtendSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long dataSize, long journalSize);
|
||||
Result DeleteCacheStorage(short index);
|
||||
Result GetCacheStorageSize(out long dataSize, out long journalSize, short index);
|
||||
@ -47,7 +47,7 @@ namespace LibHac.FsSrv
|
||||
Result OpenSaveDataInfoReader(out ReferenceCountedDisposable<ISaveDataInfoReader> infoReader);
|
||||
Result OpenSaveDataInfoReaderBySaveDataSpaceId(out ReferenceCountedDisposable<ISaveDataInfoReader> infoReader, SaveDataSpaceId spaceId);
|
||||
Result OpenSaveDataInfoReaderOnlyCacheStorage(out ReferenceCountedDisposable<ISaveDataInfoReader> infoReader);
|
||||
Result OpenSaveDataInternalStorageFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId);
|
||||
Result OpenSaveDataInternalStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, SaveDataSpaceId spaceId, ulong saveDataId);
|
||||
Result UpdateSaveDataMacForDebug(SaveDataSpaceId spaceId, ulong saveDataId);
|
||||
Result WriteSaveDataFileSystemExtraDataWithMask(ulong saveDataId, SaveDataSpaceId spaceId, ReadOnlySpan<byte> extraDataBuffer, ReadOnlySpan<byte> maskBuffer);
|
||||
Result FindSaveDataWithFilter(out long count, Span<byte> saveDataInfoBuffer, SaveDataSpaceId spaceId, ref SaveDataFilter filter);
|
||||
@ -57,16 +57,16 @@ namespace LibHac.FsSrv
|
||||
Result OpenSaveDataMetaFile(out IFile file, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute, SaveDataMetaType type);
|
||||
|
||||
Result ListAccessibleSaveDataOwnerId(out int readCount, Span<Ncm.ApplicationId> idBuffer, ProgramId programId, int startIndex, int bufferIdCount);
|
||||
Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, ImageDirectoryId directoryId);
|
||||
Result OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, ContentStorageId storageId);
|
||||
Result OpenCloudBackupWorkStorageFileSystem(out IFileSystem fileSystem, CloudBackupWorkStorageId storageId);
|
||||
Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, ImageDirectoryId directoryId);
|
||||
Result OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, ContentStorageId storageId);
|
||||
Result OpenCloudBackupWorkStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, CloudBackupWorkStorageId storageId);
|
||||
Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId);
|
||||
Result OpenDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorage> storage);
|
||||
Result OpenDataStorageByProgramId(out ReferenceCountedDisposable<IStorage> storage, ProgramId programId);
|
||||
Result OpenDataStorageByDataId(out ReferenceCountedDisposable<IStorage> storage, DataId dataId, StorageId storageId);
|
||||
Result OpenPatchDataStorageByCurrentProcess(out IStorage storage);
|
||||
Result OpenDataFileSystemWithProgramIndex(out ReferenceCountedDisposable<IFileSystem> fileSystem, byte programIndex);
|
||||
Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable<IStorage> storage, byte programIndex);
|
||||
Result OpenDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorageSf> storage);
|
||||
Result OpenDataStorageByProgramId(out ReferenceCountedDisposable<IStorageSf> storage, ProgramId programId);
|
||||
Result OpenDataStorageByDataId(out ReferenceCountedDisposable<IStorageSf> storage, DataId dataId, StorageId storageId);
|
||||
Result OpenPatchDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorageSf> storage);
|
||||
Result OpenDataFileSystemWithProgramIndex(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, byte programIndex);
|
||||
Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable<IStorageSf> storage, byte programIndex);
|
||||
Result OpenDeviceOperator(out IDeviceOperator deviceOperator);
|
||||
|
||||
Result OpenSystemDataUpdateEventNotifier(out ReferenceCountedDisposable<IEventNotifier> eventNotifier);
|
||||
@ -102,12 +102,12 @@ namespace LibHac.FsSrv
|
||||
Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode);
|
||||
Result OutputAccessLogToSdCard(U8Span logString);
|
||||
Result RegisterUpdatePartition();
|
||||
Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystem> fileSystem);
|
||||
Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystemSf> fileSystem);
|
||||
|
||||
Result GetProgramIndexForAccessLog(out int programIndex, out int programCount);
|
||||
Result OverrideSaveDataTransferTokenSignVerificationKey(ReadOnlySpan<byte> key);
|
||||
Result CorruptSaveDataFileSystemByOffset(SaveDataSpaceId spaceId, ulong saveDataId, long offset);
|
||||
Result OpenMultiCommitManager(out IMultiCommitManager commitManager);
|
||||
Result OpenBisWiper(out IWiper bisWiper, NativeHandle transferMemoryHandle, ulong transferMemorySize);
|
||||
Result OpenBisWiper(out ReferenceCountedDisposable<IWiper> bisWiper, NativeHandle transferMemoryHandle, ulong transferMemorySize);
|
||||
}
|
||||
}
|
@ -25,5 +25,9 @@ namespace LibHac.FsSrv.Impl
|
||||
wiper = new BisWiper(memoryHandle, memorySize);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
64
src/LibHac/FsSrv/Impl/DirectoryInterfaceAdapter.cs
Normal file
64
src/LibHac/FsSrv/Impl/DirectoryInterfaceAdapter.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
internal 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, Span<byte> entryBuffer)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
entriesRead = default;
|
||||
|
||||
Span<DirectoryEntry> entries = MemoryMarshal.Cast<byte, DirectoryEntry>(entryBuffer);
|
||||
|
||||
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)
|
||||
{
|
||||
entryCount = default;
|
||||
|
||||
Result rc = BaseDirectory.GetEntryCount(out long tmpEntryCount);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
entryCount = tmpEntryCount;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BaseDirectory?.Dispose();
|
||||
ParentFs?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
131
src/LibHac/FsSrv/Impl/FileInterfaceAdapter.cs
Normal file
131
src/LibHac/FsSrv/Impl/FileInterfaceAdapter.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
internal 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, Span<byte> destination, ReadOption option)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
bytesRead = default;
|
||||
|
||||
if (offset < 0)
|
||||
return ResultFs.InvalidOffset.Log();
|
||||
|
||||
if (destination.Length < 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, 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, ReadOnlySpan<byte> source, WriteOption option)
|
||||
{
|
||||
if (offset < 0)
|
||||
return ResultFs.InvalidOffset.Log();
|
||||
|
||||
if (source.Length < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
// Note: Thread priority is temporarily when writing in FS
|
||||
|
||||
return BaseFile.Write(offset, source, 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;
|
||||
size = default;
|
||||
|
||||
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)
|
||||
{
|
||||
rangeInfo = new QueryRangeInfo();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
288
src/LibHac/FsSrv/Impl/FileSystemInterfaceAdapter.cs
Normal file
288
src/LibHac/FsSrv/Impl/FileSystemInterfaceAdapter.cs
Normal file
@ -0,0 +1,288 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
internal class FileSystemInterfaceAdapter : IFileSystemSf
|
||||
{
|
||||
private ReferenceCountedDisposable<IFileSystem> BaseFileSystem { get; }
|
||||
private bool IsHostFsRoot { get; }
|
||||
|
||||
// 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)
|
||||
{
|
||||
BaseFileSystem = fileSystem;
|
||||
fileSystem = null;
|
||||
IsHostFsRoot = isHostFsRoot;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
var adapter = new FileSystemInterfaceAdapter(baseFileSystem, isHostFsRoot);
|
||||
|
||||
return ReferenceCountedDisposable<FileSystemInterfaceAdapter>.Create(adapter, out adapter._selfReference);
|
||||
}
|
||||
|
||||
/// <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> CreateSharedSfFileSystem(
|
||||
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, bool isHostFsRoot = false)
|
||||
{
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var normalizerOldPath = new PathNormalizer(new U8Span(oldPath.Str), GetPathNormalizerOption());
|
||||
if (normalizerOldPath.Result.IsFailure()) return normalizerOldPath.Result;
|
||||
|
||||
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)
|
||||
{
|
||||
var normalizerOldPath = new PathNormalizer(new U8Span(oldPath.Str), GetPathNormalizerOption());
|
||||
if (normalizerOldPath.Result.IsFailure()) return normalizerOldPath.Result;
|
||||
|
||||
var normalizerNewPath = new PathNormalizer(new U8Span(newPath.Str), GetPathNormalizerOption());
|
||||
if (normalizerNewPath.Result.IsFailure()) return normalizerNewPath.Result;
|
||||
|
||||
if (PathTool.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)
|
||||
{
|
||||
entryType = default;
|
||||
|
||||
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;
|
||||
file = default;
|
||||
|
||||
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++)
|
||||
{
|
||||
rc = BaseFileSystem.Target.OpenFile(out fileInterface, new U8Span(normalizer.Path), (OpenMode)mode);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
directory = default;
|
||||
|
||||
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++)
|
||||
{
|
||||
rc = BaseFileSystem.Target.OpenDirectory(out dirInterface, new U8Span(normalizer.Path), (OpenDirectoryMode)mode);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
return BaseFileSystem.Target.Commit();
|
||||
}
|
||||
|
||||
public Result GetFreeSpaceSize(out long freeSpace, in Path path)
|
||||
{
|
||||
freeSpace = default;
|
||||
|
||||
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)
|
||||
{
|
||||
totalSpace = default;
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
timeStamp = default;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BaseFileSystem?.Dispose();
|
||||
}
|
||||
|
||||
private PathNormalizer.Option GetPathNormalizerOption()
|
||||
{
|
||||
return IsHostFsRoot ? PathNormalizer.Option.PreserveUnc : PathNormalizer.Option.None;
|
||||
}
|
||||
}
|
||||
}
|
101
src/LibHac/FsSrv/Impl/StorageInterfaceAdapter.cs
Normal file
101
src/LibHac/FsSrv/Impl/StorageInterfaceAdapter.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
internal class StorageInterfaceAdapter : IStorageSf
|
||||
{
|
||||
private ReferenceCountedDisposable<IStorage> BaseStorage { get; }
|
||||
|
||||
public StorageInterfaceAdapter(ReferenceCountedDisposable<IStorage> baseStorage)
|
||||
{
|
||||
BaseStorage = baseStorage.AddReference();
|
||||
}
|
||||
|
||||
public Result Read(long offset, Span<byte> destination)
|
||||
{
|
||||
const int maxTryCount = 2;
|
||||
|
||||
if (offset < 0)
|
||||
return ResultFs.InvalidOffset.Log();
|
||||
|
||||
if (destination.Length < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
Result rc = Result.Success;
|
||||
|
||||
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
|
||||
{
|
||||
rc = BaseStorage.Target.Read(offset, destination);
|
||||
|
||||
// Retry on ResultDataCorrupted
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
public Result Write(long offset, ReadOnlySpan<byte> source)
|
||||
{
|
||||
if (offset < 0)
|
||||
return ResultFs.InvalidOffset.Log();
|
||||
|
||||
if (source.Length < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
// Note: Thread priority is temporarily when writing in FS
|
||||
|
||||
return BaseStorage.Target.Write(offset, source);
|
||||
}
|
||||
|
||||
public Result Flush()
|
||||
{
|
||||
return BaseStorage.Target.Flush();
|
||||
}
|
||||
|
||||
public Result SetSize(long size)
|
||||
{
|
||||
if (size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
return BaseStorage.Target.SetSize(size);
|
||||
}
|
||||
|
||||
public Result GetSize(out long size)
|
||||
{
|
||||
return BaseStorage.Target.GetSize(out size);
|
||||
}
|
||||
|
||||
public Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size)
|
||||
{
|
||||
rangeInfo = new QueryRangeInfo();
|
||||
|
||||
if (operationId == (int)OperationId.InvalidateCache)
|
||||
{
|
||||
Result rc = BaseStorage.Target.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 = BaseStorage.Target.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()
|
||||
{
|
||||
BaseStorage?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ namespace LibHac.FsSrv
|
||||
private SemaphoreAdaptor AocMountCountSemaphore { get; }
|
||||
private SemaphoreAdaptor RomMountCountSemaphore { get; }
|
||||
|
||||
public NcaFileSystemService(NcaFileSystemServiceImpl serviceImpl, ulong processId)
|
||||
private NcaFileSystemService(NcaFileSystemServiceImpl serviceImpl, ulong processId)
|
||||
{
|
||||
ServiceImpl = serviceImpl;
|
||||
ProcessId = processId;
|
||||
@ -30,19 +30,33 @@ namespace LibHac.FsSrv
|
||||
RomMountCountSemaphore = new SemaphoreAdaptor(RomSemaphoreCount, RomSemaphoreCount);
|
||||
}
|
||||
|
||||
public Result OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public static ReferenceCountedDisposable<NcaFileSystemService> Create(NcaFileSystemServiceImpl serviceImpl,
|
||||
ulong processId)
|
||||
{
|
||||
// Create the service
|
||||
var ncaService = new NcaFileSystemService(serviceImpl, processId);
|
||||
|
||||
// Wrap the service in a ref-counter and give the service a weak self-reference
|
||||
var sharedService = new ReferenceCountedDisposable<NcaFileSystemService>(ncaService);
|
||||
ncaService.SelfReference =
|
||||
new ReferenceCountedDisposable<NcaFileSystemService>.WeakReference(sharedService);
|
||||
|
||||
return sharedService;
|
||||
}
|
||||
|
||||
public Result OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
ProgramId programId, FileSystemProxyType fsType)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
out CodeVerificationData verificationData, in FspPath path, ProgramId programId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenDataFileSystemByCurrentProcess(out ReferenceCountedDisposable<IFileSystem> fileSystem)
|
||||
public Result OpenDataFileSystemByCurrentProcess(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@ -53,17 +67,17 @@ namespace LibHac.FsSrv
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorage> storage)
|
||||
public Result OpenDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorageSf> storage)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenDataStorageByProgramId(out ReferenceCountedDisposable<IStorage> storage, ProgramId programId)
|
||||
public Result OpenDataStorageByProgramId(out ReferenceCountedDisposable<IStorageSf> storage, ProgramId programId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystem> fileSystem, in FspPath path,
|
||||
public Result OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath path,
|
||||
ulong id, FileSystemProxyType fsType)
|
||||
{
|
||||
fileSystem = default;
|
||||
@ -117,33 +131,44 @@ namespace LibHac.FsSrv
|
||||
var normalizer = new PathNormalizer(path, GetPathNormalizerOptions(path));
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
rc = ServiceImpl.OpenFileSystem(out ReferenceCountedDisposable<IFileSystem> baseFs, out _, path, fsType,
|
||||
canMountSystemDataPrivate, id);
|
||||
if (rc.IsFailure()) return rc;
|
||||
ReferenceCountedDisposable<IFileSystem> fs = null;
|
||||
|
||||
fileSystem = baseFs;
|
||||
return Result.Success;
|
||||
try
|
||||
{
|
||||
rc = ServiceImpl.OpenFileSystem(out fs, out _, path, fsType,
|
||||
canMountSystemDataPrivate, id);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Create an SF adapter for the file system
|
||||
fileSystem = FileSystemInterfaceAdapter.CreateSharedSfFileSystem(ref fs);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result OpenDataFileSystemByProgramId(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenDataFileSystemByProgramId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
ProgramId programId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenDataStorageByDataId(out ReferenceCountedDisposable<IStorage> storage, DataId dataId,
|
||||
public Result OpenDataStorageByDataId(out ReferenceCountedDisposable<IStorageSf> storage, DataId dataId,
|
||||
StorageId storageId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenDataFileSystemWithProgramIndex(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenDataFileSystemWithProgramIndex(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
byte programIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable<IStorage> storage,
|
||||
public Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable<IStorageSf> storage,
|
||||
byte programIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@ -165,7 +190,7 @@ namespace LibHac.FsSrv
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
public Result OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
ContentStorageId contentStorageId)
|
||||
{
|
||||
fileSystem = default;
|
||||
@ -179,12 +204,22 @@ namespace LibHac.FsSrv
|
||||
if (!accessibility.CanRead || !accessibility.CanWrite)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
rc = ServiceImpl.OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> contentFs,
|
||||
contentStorageId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
ReferenceCountedDisposable<IFileSystem> fs = null;
|
||||
|
||||
fileSystem = contentFs;
|
||||
return Result.Success;
|
||||
try
|
||||
{
|
||||
rc = ServiceImpl.OpenContentStorageFileSystem(out fs, contentStorageId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Create an SF adapter for the file system
|
||||
fileSystem = FileSystemInterfaceAdapter.CreateSharedSfFileSystem(ref fs);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fs?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result RegisterExternalKey(in RightsId rightsId, in AccessKey accessKey)
|
||||
@ -225,7 +260,7 @@ namespace LibHac.FsSrv
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystem> fileSystem)
|
||||
public Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@ -282,11 +317,6 @@ namespace LibHac.FsSrv
|
||||
return OpenDataStorageCore(out storage, out ncaHeaderDigest, id, storageId);
|
||||
}
|
||||
|
||||
internal void SetSelfReference(ReferenceCountedDisposable<NcaFileSystemService> reference)
|
||||
{
|
||||
SelfReference = new ReferenceCountedDisposable<NcaFileSystemService>.WeakReference(reference);
|
||||
}
|
||||
|
||||
private Result TryAcquireAddOnContentOpenCountSemaphore(out IUniqueLock semaphoreLock)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
10
src/LibHac/FsSrv/Sf/IDirectory.cs
Normal file
10
src/LibHac/FsSrv/Sf/IDirectory.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac.FsSrv.Sf
|
||||
{
|
||||
public interface IDirectorySf : IDisposable
|
||||
{
|
||||
Result Read(out long entriesRead, Span<byte> entryBuffer);
|
||||
Result GetEntryCount(out long entryCount);
|
||||
}
|
||||
}
|
15
src/LibHac/FsSrv/Sf/IFile.cs
Normal file
15
src/LibHac/FsSrv/Sf/IFile.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.Sf
|
||||
{
|
||||
public interface IFileSf : IDisposable
|
||||
{
|
||||
Result Read(out long bytesRead, long offset, Span<byte> destination, ReadOption option);
|
||||
Result Write(long offset, ReadOnlySpan<byte> source, WriteOption option);
|
||||
Result Flush();
|
||||
Result SetSize(long size);
|
||||
Result GetSize(out long size);
|
||||
Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size);
|
||||
}
|
||||
}
|
27
src/LibHac/FsSrv/Sf/IFileSystem.cs
Normal file
27
src/LibHac/FsSrv/Sf/IFileSystem.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
|
||||
namespace LibHac.FsSrv.Sf
|
||||
{
|
||||
public interface IFileSystemSf : IDisposable
|
||||
{
|
||||
Result GetImpl(out ReferenceCountedDisposable<IFileSystem> fileSystem);
|
||||
Result CreateFile(in Path path, long size, int option);
|
||||
Result DeleteFile(in Path path);
|
||||
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 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);
|
||||
Result Commit();
|
||||
Result GetFreeSpaceSize(out long freeSpace, in Path path);
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Ncm;
|
||||
|
||||
namespace LibHac.FsSrv.Sf
|
||||
{
|
||||
public interface IFileSystemProxyForLoader
|
||||
{
|
||||
Result OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
|
||||
Result OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
|
||||
out CodeVerificationData verificationData, in FspPath path, ProgramId programId);
|
||||
|
||||
Result IsArchivedProgram(out bool isArchived, ulong processId);
|
||||
|
15
src/LibHac/FsSrv/Sf/IStorage.cs
Normal file
15
src/LibHac/FsSrv/Sf/IStorage.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.Sf
|
||||
{
|
||||
public interface IStorageSf : IDisposable
|
||||
{
|
||||
Result Read(long offset, Span<byte> destination);
|
||||
Result Write(long offset, ReadOnlySpan<byte> source);
|
||||
Result Flush();
|
||||
Result SetSize(long size);
|
||||
Result GetSize(out long size);
|
||||
Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size);
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
namespace LibHac.FsSrv.Sf
|
||||
using System;
|
||||
|
||||
namespace LibHac.FsSrv.Sf
|
||||
{
|
||||
public interface IWiper
|
||||
public interface IWiper : IDisposable
|
||||
{
|
||||
public Result Startup(out long spaceToWipe);
|
||||
public Result Process(out long remainingSpaceToWipe);
|
||||
|
21
src/LibHac/FsSrv/Sf/Path.cs
Normal file
21
src/LibHac/FsSrv/Sf/Path.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.Sf
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = PathTool.EntryNameLengthMax + 1)]
|
||||
public readonly struct Path
|
||||
{
|
||||
#if DEBUG
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding000;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding100;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding200;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte Padding300;
|
||||
#endif
|
||||
|
||||
public ReadOnlySpan<byte> Str => SpanHelpers.AsReadOnlyByteSpan(in this);
|
||||
}
|
||||
}
|
15
src/LibHac/FsSrv/Storage/IGameCardDeviceManager.cs
Normal file
15
src/LibHac/FsSrv/Storage/IGameCardDeviceManager.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using LibHac.Fs.Impl;
|
||||
|
||||
namespace LibHac.FsSrv.Storage
|
||||
{
|
||||
internal interface IGameCardDeviceManager
|
||||
{
|
||||
Result AcquireReadLock(out UniqueLock locker, uint handle);
|
||||
Result AcquireReadLockSecureMode(out UniqueLock locker, ref uint handle, ReadOnlySpan<byte> cardDeviceId, ReadOnlySpan<byte> cardImageHash);
|
||||
Result AcquireWriteLock(out SharedLock locker);
|
||||
Result HandleGameCardAccessResult(Result result);
|
||||
Result GetHandle(out uint handle);
|
||||
bool IsSecureMode();
|
||||
}
|
||||
}
|
9
src/LibHac/FsSrv/Storage/IGameCardKeyManager.cs
Normal file
9
src/LibHac/FsSrv/Storage/IGameCardKeyManager.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac.FsSrv.Storage
|
||||
{
|
||||
public interface IGameCardKeyManager
|
||||
{
|
||||
void PresetInternalKeys(ReadOnlySpan<byte> gameCardKey, ReadOnlySpan<byte> gameCardCertificate);
|
||||
}
|
||||
}
|
12
src/LibHac/FsSrv/Storage/ISdmmcDeviceManager.cs
Normal file
12
src/LibHac/FsSrv/Storage/ISdmmcDeviceManager.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.Storage
|
||||
{
|
||||
internal interface ISdmmcDeviceManager
|
||||
{
|
||||
Result Lock(out object locker, uint handle);
|
||||
IStorage GetStorage();
|
||||
SdmmcPort GetPortId();
|
||||
Result NotifyCloseStorageDevice(uint handle);
|
||||
}
|
||||
}
|
18
src/LibHac/FsSrv/Storage/Sf/IStorageDevice.cs
Normal file
18
src/LibHac/FsSrv/Storage/Sf/IStorageDevice.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.Storage.Sf
|
||||
{
|
||||
public interface IStorageDevice : IDisposable
|
||||
{
|
||||
Result GetHandle(out uint handle);
|
||||
Result IsHandleValid(out bool isValid);
|
||||
Result OpenOperator(out ReferenceCountedDisposable<IStorageDeviceOperator> deviceOperator);
|
||||
Result Read(long offset, Span<byte> destination);
|
||||
Result Write(long offset, ReadOnlySpan<byte> source);
|
||||
Result Flush();
|
||||
Result SetSize(long size);
|
||||
Result GetSize(out long size);
|
||||
Result OperateRange(out QueryRangeInfo rangeInfo, int operationId, long offset, long size);
|
||||
}
|
||||
}
|
21
src/LibHac/FsSrv/Storage/Sf/IStorageDeviceManager.cs
Normal file
21
src/LibHac/FsSrv/Storage/Sf/IStorageDeviceManager.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSrv.Sf;
|
||||
|
||||
namespace LibHac.FsSrv.Storage.Sf
|
||||
{
|
||||
public interface IStorageDeviceManager : IDisposable
|
||||
{
|
||||
Result IsInserted(out bool isInserted);
|
||||
Result IsHandleValid(out bool isValid, uint handle);
|
||||
Result OpenDetectionEvent(out ReferenceCountedDisposable<IEventNotifier> eventNotifier);
|
||||
Result OpenOperator(out ReferenceCountedDisposable<IStorageDeviceOperator> deviceOperator);
|
||||
Result OpenDevice(out ReferenceCountedDisposable<IStorageDevice> storageDevice, ulong attribute);
|
||||
Result OpenStorage(out ReferenceCountedDisposable<IStorage> storage, ulong attribute);
|
||||
Result PutToSleep();
|
||||
Result Awaken();
|
||||
Result Initialize();
|
||||
Result Shutdown();
|
||||
Result Invalidate();
|
||||
}
|
||||
}
|
14
src/LibHac/FsSrv/Storage/Sf/IStorageDeviceOperator.cs
Normal file
14
src/LibHac/FsSrv/Storage/Sf/IStorageDeviceOperator.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac.FsSrv.Storage.Sf
|
||||
{
|
||||
public interface IStorageDeviceOperator : IDisposable
|
||||
{
|
||||
Result Operate(uint operationId);
|
||||
Result OperateIn(ReadOnlySpan<byte> buffer, long offset, long size, uint operationId);
|
||||
Result OperateOut(out long bytesWritten, Span<byte> buffer, long offset, long size, uint operationId);
|
||||
Result OperateOut2(out long bytesWrittenBuffer1, Span<byte> buffer1, out long bytesWrittenBuffer2, Span<byte> buffer2, uint operationId);
|
||||
Result OperateInOut(out long bytesWritten, Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, long offset, long size, uint operationId);
|
||||
Result OperateIn2Out(out long bytesWritten, Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer1, ReadOnlySpan<byte> inBuffer2, long offset, long size, uint operationId);
|
||||
}
|
||||
}
|
@ -61,7 +61,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
if (PathTool.IsSubpath(normalizedPath1, normalizedPath2))
|
||||
{
|
||||
return ResultFs.DestinationIsSubPathOfSource.Log();
|
||||
return ResultFs.DirectoryNotRenamable.Log();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
|
@ -347,7 +347,7 @@ namespace LibHac.FsSystem.Save
|
||||
|
||||
if (PathTools.IsSubPath(srcPath, dstPath))
|
||||
{
|
||||
return ResultFs.DestinationIsSubPathOfSource.Log();
|
||||
return ResultFs.DirectoryNotRenamable.Log();
|
||||
}
|
||||
|
||||
if (oldKey.Parent != newKey.Parent)
|
||||
|
@ -8,6 +8,7 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace LibHac
|
||||
@ -26,14 +27,14 @@ namespace LibHac
|
||||
/// released through either of the following actions:</para>
|
||||
///
|
||||
/// <list type="bullet">
|
||||
/// <item>The reference is explicitly released by a call to <see cref="Dispose"/>.</item>
|
||||
/// <item>The reference is explicitly released by a call to <see cref="Dispose()"/>.</item>
|
||||
/// <item>The reference is no longer in use by managed code and gets reclaimed by the garbage collector.</item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para>While each instance of <see cref="ReferenceCountedDisposable{T}"/> should be explicitly disposed when
|
||||
/// the object is no longer needed by the code owning the reference, this implementation will not leak resources
|
||||
/// in the event one or more callers fail to do so. When all references to an object are explicitly released
|
||||
/// (i.e. by calling <see cref="Dispose"/>), the target object will itself be deterministically released by a
|
||||
/// (i.e. by calling <see cref="Dispose()"/>), the target object will itself be deterministically released by a
|
||||
/// call to <see cref="IDisposable.Dispose"/> when the last reference to it is released. However, in the event
|
||||
/// one or more references is not explicitly released, the underlying object will still become eligible for
|
||||
/// non-deterministic release (i.e. finalization) as soon as each reference to it is released by one of the
|
||||
@ -65,7 +66,7 @@ namespace LibHac
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This value is only cleared in order to support cases where one or more references is garbage
|
||||
/// collected without having <see cref="Dispose"/> called.</para>
|
||||
/// collected without having <see cref="Dispose()"/> called.</para>
|
||||
/// </remarks>
|
||||
private T? _instance;
|
||||
|
||||
@ -110,16 +111,37 @@ namespace LibHac
|
||||
/// Gets the target object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This call is not valid after <see cref="Dispose"/> is called. If this property or the target
|
||||
/// object is used concurrently with a call to <see cref="Dispose"/>, it is possible for the code to be
|
||||
/// <para>This call is not valid after <see cref="Dispose()"/> is called. If this property or the target
|
||||
/// object is used concurrently with a call to <see cref="Dispose()"/>, it is possible for the code to be
|
||||
/// using a disposed object. After the current instance is disposed, this property throws
|
||||
/// <see cref="ObjectDisposedException"/>. However, the exact time when this property starts throwing after
|
||||
/// <see cref="Dispose"/> is called is unspecified; code is expected to not use this property or the object
|
||||
/// it returns after any code invokes <see cref="Dispose"/>.</para>
|
||||
/// <see cref="Dispose()"/> is called is unspecified; code is expected to not use this property or the object
|
||||
/// it returns after any code invokes <see cref="Dispose()"/>.</para>
|
||||
/// </remarks>
|
||||
/// <value>The target object.</value>
|
||||
public T Target => _instance ?? throw new ObjectDisposedException(nameof(ReferenceCountedDisposable<T>));
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new reference counting wrapper around an <see cref="IDisposable"/> object.
|
||||
/// Returns a reference counting wrapper of the base type of the input object, and creates a
|
||||
/// <see cref="WeakReference"/> of the object's derived type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDerived">The derived type of the object to be wrapped.</typeparam>
|
||||
/// <param name="instance">The object owned by this wrapper.</param>
|
||||
/// <param name="derivedWeakReference">The weak reference of the derived type.</param>
|
||||
/// <returns></returns>
|
||||
public static ReferenceCountedDisposable<T> Create<TDerived>(TDerived instance,
|
||||
out ReferenceCountedDisposable<TDerived>.WeakReference derivedWeakReference)
|
||||
where TDerived : class, IDisposable, T
|
||||
{
|
||||
var baseStrongRef = new ReferenceCountedDisposable<T>(instance);
|
||||
|
||||
derivedWeakReference =
|
||||
new ReferenceCountedDisposable<TDerived>.WeakReference(instance, baseStrongRef._boxedReferenceCount);
|
||||
|
||||
return baseStrongRef;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increments the reference count for the disposable object, and returns a new disposable reference to it.
|
||||
/// </summary>
|
||||
@ -272,6 +294,11 @@ namespace LibHac
|
||||
}
|
||||
}
|
||||
|
||||
// Print info on non-disposed references in debug mode
|
||||
#if DEBUG
|
||||
~ReferenceCountedDisposable() => Dispose(false);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Releases the current reference, causing the underlying object to be disposed if this was the last
|
||||
/// reference.
|
||||
@ -283,26 +310,42 @@ namespace LibHac
|
||||
/// </remarks>
|
||||
public void Dispose()
|
||||
{
|
||||
T? instanceToDispose = null;
|
||||
lock (_boxedReferenceCount)
|
||||
Dispose(true);
|
||||
|
||||
#if DEBUG
|
||||
GC.SuppressFinalize(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_instance == null)
|
||||
T? instanceToDispose = null;
|
||||
lock (_boxedReferenceCount)
|
||||
{
|
||||
// Already disposed; allow multiple without error.
|
||||
return;
|
||||
if (_instance == null)
|
||||
{
|
||||
// Already disposed; allow multiple without error.
|
||||
return;
|
||||
}
|
||||
|
||||
_boxedReferenceCount.Value--;
|
||||
if (_boxedReferenceCount.Value == 0)
|
||||
{
|
||||
instanceToDispose = _instance;
|
||||
}
|
||||
|
||||
// Ensure multiple calls to Dispose for this instance are a NOP.
|
||||
_instance = null;
|
||||
}
|
||||
|
||||
_boxedReferenceCount.Value--;
|
||||
if (_boxedReferenceCount.Value == 0)
|
||||
{
|
||||
instanceToDispose = _instance;
|
||||
}
|
||||
|
||||
// Ensure multiple calls to Dispose for this instance are a NOP.
|
||||
_instance = null;
|
||||
instanceToDispose?.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.WriteLine($"Failed to dispose object with type {GetType().FullName}.");
|
||||
}
|
||||
|
||||
instanceToDispose?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -349,6 +392,24 @@ namespace LibHac
|
||||
_boxedReferenceCount = referenceCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="instance"></param>
|
||||
/// <param name="referenceCount"></param>
|
||||
internal WeakReference(T instance, StrongBox<int> referenceCount)
|
||||
{
|
||||
// This constructor is meant for internal use when creating a weak reference
|
||||
// to an instance that is already wrapped by a ReferenceCountedDisposable.
|
||||
if (instance == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(instance));
|
||||
}
|
||||
|
||||
_weakInstance = new WeakReference<T>(instance);
|
||||
_boxedReferenceCount = referenceCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increments the reference count for the disposable object, and returns a new disposable reference to
|
||||
/// it.
|
||||
|
Loading…
x
Reference in New Issue
Block a user