Make FileSystemProxy implement IFileSystemProxy

This commit is contained in:
Alex Barney 2019-09-23 18:37:23 -05:00
parent fd40b2fd77
commit c89bc1c706
8 changed files with 499 additions and 76 deletions

View file

@ -33,6 +33,18 @@ namespace LibHac.Common
return i;
}
public static int GetLength(ReadOnlySpan<byte> s, int maxLen)
{
int i = 0;
while (i < maxLen && i < s.Length && s[i] != 0)
{
i++;
}
return i;
}
/// <summary>
/// Concatenates 2 byte strings.
/// </summary>

View file

@ -20,7 +20,7 @@ namespace LibHac.Fs
Result rc = MountHelpers.CheckMountNameAcceptingReservedMountName(mountName);
if (rc.IsFailure()) return rc;
FileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
rc = fsProxy.OpenContentStorageFileSystem(out IFileSystem contentFs, storageId);
if (rc.IsFailure()) return rc;

View file

@ -11,7 +11,7 @@ namespace LibHac.Fs
Result rc = MountHelpers.CheckMountName(mountName);
if (rc.IsFailure()) return rc;
FileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
rc = fsProxy.OpenCustomStorageFileSystem(out IFileSystem customFs, storageId);
if (rc.IsFailure()) return rc;

View file

@ -6,7 +6,7 @@ namespace LibHac.Fs
public partial class FileSystemClient
{
private FileSystemServer FsSrv { get; }
private FileSystemProxy FsProxy { get; set; }
private IFileSystemProxy FsProxy { get; set; }
private FileSystemManager FsManager { get; }
private readonly object _fspInitLocker = new object();
@ -17,7 +17,7 @@ namespace LibHac.Fs
FsManager = new FileSystemManager(timer);
}
public FileSystemProxy GetFileSystemProxyServiceObject()
public IFileSystemProxy GetFileSystemProxyServiceObject()
{
if (FsProxy != null) return FsProxy;

View file

@ -2,10 +2,12 @@
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.Ncm;
using LibHac.Spl;
namespace LibHac.FsService
{
public class FileSystemProxy
public class FileSystemProxy : IFileSystemProxy
{
private FileSystemProxyCore FsProxyCore { get; }
@ -17,7 +19,7 @@ namespace LibHac.FsService
public long SaveDataSize { get; private set; }
public long SaveDataJournalSize { get; private set; }
public string SaveDataRootPath { get; private set; }
public FsPath SaveDataRootPath { get; } = default;
public bool AutoCreateSaveData { get; private set; }
private const ulong SaveIndexerId = 0x8000000000000000;
@ -30,10 +32,19 @@ namespace LibHac.FsService
CurrentProcess = -1;
SaveDataSize = 0x2000000;
SaveDataJournalSize = 0x1000000;
SaveDataRootPath = string.Empty;
AutoCreateSaveData = true;
}
public Result OpenFileSystemWithId(out IFileSystem fileSystem, ref FsPath path, TitleId titleId, FileSystemType type)
{
throw new NotImplementedException();
}
public Result OpenFileSystemWithPatch(out IFileSystem fileSystem, TitleId titleId, FileSystemType type)
{
throw new NotImplementedException();
}
public Result SetCurrentProcess(long processId)
{
CurrentProcess = processId;
@ -41,104 +52,100 @@ namespace LibHac.FsService
return Result.Success;
}
public Result DisableAutoSaveDataCreation()
public Result GetFreeSpaceSizeForSaveData(out long freeSpaceSize, SaveDataSpaceId spaceId)
{
AutoCreateSaveData = false;
return Result.Success;
throw new NotImplementedException();
}
public Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize)
public Result OpenDataFileSystemByCurrentProcess(out IFileSystem fileSystem)
{
if (saveDataSize < 0 || saveDataJournalSize < 0)
{
return ResultFs.InvalidSize;
throw new NotImplementedException();
}
SaveDataSize = saveDataSize;
SaveDataJournalSize = saveDataJournalSize;
return Result.Success;
public Result OpenDataFileSystemByProgramId(out IFileSystem fileSystem, TitleId titleId)
{
throw new NotImplementedException();
}
public Result SetSaveDataRootPath(string path)
public Result OpenDataStorageByCurrentProcess(out IStorage storage)
{
// Missing permission check
if (path.Length > PathTools.MaxPathLength)
{
return ResultFs.TooLongPath;
throw new NotImplementedException();
}
SaveDataRootPath = path;
return Result.Success;
public Result OpenDataStorageByProgramId(out IStorage storage, TitleId programId)
{
throw new NotImplementedException();
}
public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId)
public Result OpenDataStorageByDataId(out IStorage storage, TitleId dataId, StorageId storageId)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
return FsProxyCore.OpenBisFileSystem(out fileSystem, rootPath, partitionId);
throw new NotImplementedException();
}
public Result OpenSdCardFileSystem(out IFileSystem fileSystem)
public Result OpenPatchDataStorageByCurrentProcess(out IStorage storage)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
return FsProxyCore.OpenSdCardFileSystem(out fileSystem);
throw new NotImplementedException();
}
public Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId)
public Result OpenDataFileSystemWithProgramIndex(out IFileSystem fileSystem, byte programIndex)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId);
throw new NotImplementedException();
}
public Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId)
public Result OpenDataStorageWithProgramIndex(out IStorage storage, byte programIndex)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
return FsProxyCore.OpenCustomStorageFileSystem(out fileSystem, storageId);
throw new NotImplementedException();
}
public Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId,
SaveDataAttribute attribute)
public Result RegisterSaveDataFileSystemAtomicDeletion(ReadOnlySpan<ulong> saveDataIds)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
fileSystem = default;
if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log();
Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out _, spaceId,
attribute, false, true);
if (rc.IsFailure()) return rc;
// Missing check if the current title owns the save data or can open it
fileSystem = saveFs;
return Result.Success;
throw new NotImplementedException();
}
public Result SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed)
public Result DeleteSaveDataFileSystem(ulong saveDataId)
{
// todo: use struct instead of byte span
if (seed.Length != 0x10) return ResultFs.InvalidSize;
throw new NotImplementedException();
}
// Missing permission check
public Result DeleteSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId)
{
throw new NotImplementedException();
}
Result rc = FsProxyCore.SetSdCardEncryptionSeed(seed);
if (rc.IsFailure()) return rc;
public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute)
{
throw new NotImplementedException();
}
// todo: Reset save data indexer
public Result UpdateSaveDataMacForDebug(SaveDataSpaceId spaceId, ulong saveDataId)
{
throw new NotImplementedException();
}
return Result.Success;
public Result CreateSaveDataFileSystem(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo,
ref SaveMetaCreateInfo metaCreateInfo)
{
throw new NotImplementedException();
}
public Result CreateSaveDataFileSystemWithHashSalt(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo,
ref SaveMetaCreateInfo metaCreateInfo, ref HashSalt hashSalt)
{
throw new NotImplementedException();
}
public Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo)
{
throw new NotImplementedException();
}
public Result ExtendSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long dataSize, long journalSize)
{
throw new NotImplementedException();
}
private Result OpenSaveDataFileSystemImpl(out IFileSystem fileSystem, out ulong saveDataId,
SaveDataSpaceId spaceId, SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData)
SaveDataSpaceId spaceId, ref SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData)
{
bool hasFixedId = attribute.SaveId != 0 && attribute.UserId.Id == Id128.InvalidId;
@ -152,7 +159,7 @@ namespace LibHac.FsService
}
Result saveFsResult = FsProxyCore.OpenSaveDataFileSystem(out fileSystem, spaceId, saveDataId,
SaveDataRootPath, openReadOnly, attribute.Type, cacheExtraData);
SaveDataRootPath.ToString(), openReadOnly, attribute.Type, cacheExtraData);
if (saveFsResult.IsSuccess()) return Result.Success;
@ -170,7 +177,395 @@ namespace LibHac.FsService
return ResultFs.TargetNotFound;
}
private bool IsSystemSaveDataId(ulong id)
public Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute)
{
throw new NotImplementedException();
}
public Result OpenReadOnlySaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId,
ref SaveDataAttribute attribute)
{
throw new NotImplementedException();
}
public Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId,
ref SaveDataAttribute attribute)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
fileSystem = default;
if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log();
Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out _, spaceId,
ref attribute, false, true);
if (rc.IsFailure()) return rc;
// Missing check if the current title owns the save data or can open it
fileSystem = saveFs;
return Result.Success;
}
public Result ReadSaveDataFileSystemExtraData(Span<byte> extraDataBuffer, ulong saveDataId)
{
throw new NotImplementedException();
}
public Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(Span<byte> extraDataBuffer, SaveDataSpaceId spaceId,
ulong saveDataId)
{
throw new NotImplementedException();
}
public Result ReadSaveDataFileSystemExtraDataBySaveDataAttribute(Span<byte> extraDataBuffer, SaveDataSpaceId spaceId,
ref SaveDataAttribute2 attribute)
{
throw new NotImplementedException();
}
public Result WriteSaveDataFileSystemExtraData(ulong saveDataId, SaveDataSpaceId spaceId, ReadOnlySpan<byte> extraDataBuffer)
{
throw new NotImplementedException();
}
public Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute(ref SaveDataAttribute2 attribute, SaveDataSpaceId spaceId,
ReadOnlySpan<byte> extraDataBuffer, ReadOnlySpan<byte> maskBuffer)
{
throw new NotImplementedException();
}
public Result WriteSaveDataFileSystemExtraDataWithMask(ulong saveDataId, SaveDataSpaceId spaceId, ReadOnlySpan<byte> extraDataBuffer,
ReadOnlySpan<byte> maskBuffer)
{
throw new NotImplementedException();
}
public Result OpenImageDirectoryFileSystem(out IFileSystem fileSystem, ImageDirectoryId dirId)
{
throw new NotImplementedException();
}
public Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path)
{
throw new NotImplementedException();
}
public Result OpenBisFileSystem(out IFileSystem fileSystem, ref FsPath rootPath, BisPartitionId partitionId)
{
fileSystem = default;
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
Result rc = PathTools.Normalize(out U8Span normalizedPath, rootPath);
if (rc.IsFailure()) return rc;
return FsProxyCore.OpenBisFileSystem(out fileSystem, normalizedPath.ToString(), partitionId);
}
public Result OpenBisStorage(out IStorage storage, BisPartitionId partitionId)
{
throw new NotImplementedException();
}
public Result InvalidateBisCache()
{
throw new NotImplementedException();
}
public Result OpenHostFileSystem(out IFileSystem fileSystem, ref FsPath subPath)
{
throw new NotImplementedException();
}
public Result OpenSdCardFileSystem(out IFileSystem fileSystem)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
return FsProxyCore.OpenSdCardFileSystem(out fileSystem);
}
public Result FormatSdCardFileSystem()
{
throw new NotImplementedException();
}
public Result FormatSdCardDryRun()
{
throw new NotImplementedException();
}
public Result IsExFatSupported(out bool isSupported)
{
throw new NotImplementedException();
}
public Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId)
{
throw new NotImplementedException();
}
public Result OpenDeviceOperator(out IDeviceOperator deviceOperator)
{
throw new NotImplementedException();
}
public Result OpenSaveDataInfoReader(out ISaveDataInfoReader infoReader)
{
throw new NotImplementedException();
}
public Result OpenSaveDataInfoReaderBySaveDataSpaceId(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId)
{
throw new NotImplementedException();
}
public Result OpenSaveDataInfoReaderWithFilter(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId,
ref SaveDataFilter filter)
{
throw new NotImplementedException();
}
public Result FindSaveDataWithFilter(out long count, Span<byte> saveDataInfoBuffer, SaveDataSpaceId spaceId,
ref SaveDataFilter filter)
{
throw new NotImplementedException();
}
public Result OpenSaveDataInternalStorageFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId)
{
throw new NotImplementedException();
}
public Result QuerySaveDataInternalStorageTotalSize(out long size, SaveDataSpaceId spaceId, ulong saveDataId)
{
throw new NotImplementedException();
}
public Result GetSaveDataCommitId(out long commitId, SaveDataSpaceId spaceId, ulong saveDataId)
{
throw new NotImplementedException();
}
public Result OpenSaveDataInfoReaderOnlyCacheStorage(out ISaveDataInfoReader infoReader)
{
throw new NotImplementedException();
}
public Result OpenSaveDataMetaFile(out IFile file, SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute,
SaveMetaType type)
{
throw new NotImplementedException();
}
public Result DeleteCacheStorage(short index)
{
throw new NotImplementedException();
}
public Result GetCacheStorageSize(out long dataSize, out long journalSize, short index)
{
throw new NotImplementedException();
}
public Result ListAccessibleSaveDataOwnerId(out int readCount, Span<TitleId> idBuffer, TitleId programId, int startIndex,
int bufferIdCount)
{
throw new NotImplementedException();
}
public Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize)
{
if (saveDataSize < 0 || saveDataJournalSize < 0)
{
return ResultFs.InvalidSize;
}
SaveDataSize = saveDataSize;
SaveDataJournalSize = saveDataJournalSize;
return Result.Success;
}
public Result SetSaveDataRootPath(ref FsPath path)
{
// Missing permission check
if (StringUtils.GetLength(path.Str, FsPath.MaxLength + 1) > FsPath.MaxLength)
{
return ResultFs.TooLongPath;
}
StringUtils.Copy(SaveDataRootPath.Str, path.Str);
return Result.Success;
}
public Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId);
}
public Result OpenCloudBackupWorkStorageFileSystem(out IFileSystem fileSystem, CloudBackupWorkStorageId storageId)
{
throw new NotImplementedException();
}
public Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId)
{
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
return FsProxyCore.OpenCustomStorageFileSystem(out fileSystem, storageId);
}
public Result OpenGameCardFileSystem(out IFileSystem fileSystem, GameCardHandle handle, GameCardPartition partitionId)
{
throw new NotImplementedException();
}
public Result QuerySaveDataTotalSize(out long totalSize, long dataSize, long journalSize)
{
throw new NotImplementedException();
}
public Result SetCurrentPosixTimeWithTimeDifference(long time, int difference)
{
throw new NotImplementedException();
}
public Result GetRightsId(out RightsId rightsId, TitleId programId, StorageId storageId)
{
throw new NotImplementedException();
}
public Result GetRightsIdByPath(out RightsId rightsId, ref FsPath path)
{
throw new NotImplementedException();
}
public Result GetRightsIdAndKeyGenerationByPath(out RightsId rightsId, out byte keyGeneration, ref FsPath path)
{
throw new NotImplementedException();
}
public Result RegisterExternalKey(ref RightsId rightsId, ref AccessKey externalKey)
{
throw new NotImplementedException();
}
public Result UnregisterExternalKey(ref RightsId rightsId)
{
throw new NotImplementedException();
}
public Result UnregisterAllExternalKey()
{
throw new NotImplementedException();
}
public Result SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed)
{
// todo: use struct instead of byte span
if (seed.Length != 0x10) return ResultFs.InvalidSize;
// Missing permission check
Result rc = FsProxyCore.SetSdCardEncryptionSeed(seed);
if (rc.IsFailure()) return rc;
// todo: Reset save data indexer
return Result.Success;
}
public Result VerifySaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId, Span<byte> readBuffer)
{
throw new NotImplementedException();
}
public Result VerifySaveDataFileSystem(ulong saveDataId, Span<byte> readBuffer)
{
throw new NotImplementedException();
}
public Result CorruptSaveDataFileSystemByOffset(SaveDataSpaceId spaceId, ulong saveDataId, long offset)
{
throw new NotImplementedException();
}
public Result CorruptSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId)
{
throw new NotImplementedException();
}
public Result CorruptSaveDataFileSystem(ulong saveDataId)
{
throw new NotImplementedException();
}
public Result CreatePaddingFile(long size)
{
throw new NotImplementedException();
}
public Result DeleteAllPaddingFiles()
{
throw new NotImplementedException();
}
public Result DisableAutoSaveDataCreation()
{
AutoCreateSaveData = false;
return Result.Success;
}
public Result SetGlobalAccessLogMode(int mode)
{
throw new NotImplementedException();
}
public Result GetGlobalAccessLogMode(out int mode)
{
throw new NotImplementedException();
}
public Result GetProgramIndexForAccessLog(out int programIndex, out int programCount)
{
throw new NotImplementedException();
}
public Result OutputAccessLogToSdCard(U8Span logString)
{
throw new NotImplementedException();
}
public Result RegisterUpdatePartition()
{
throw new NotImplementedException();
}
public Result OpenRegisteredUpdatePartition(out IFileSystem fileSystem)
{
throw new NotImplementedException();
}
public Result OverrideSaveDataTransferTokenSignVerificationKey(ReadOnlySpan<byte> key)
{
throw new NotImplementedException();
}
public Result SetSdCardAccessibility(bool isAccessible)
{
throw new NotImplementedException();
}
public Result IsSdCardAccessible(out bool isAccessible)
{
throw new NotImplementedException();
}
private static bool IsSystemSaveDataId(ulong id)
{
return (long)id < 0;
}

View file

@ -47,7 +47,7 @@ namespace LibHac.FsService
return new FileSystemClient(this, timer);
}
public FileSystemProxy CreateFileSystemProxyService()
public IFileSystemProxy CreateFileSystemProxyService()
{
return new FileSystemProxy(FsProxyCore, FsClient);
}

View file

@ -15,6 +15,7 @@ namespace LibHac.FsSystem
public Span<byte> Str => SpanHelpers.CreateSpan(ref _str, MaxLength + 1);
public static implicit operator U8Span(FsPath value) => new U8Span(value.Str);
public override string ToString() => StringUtils.Utf8ZToString(Str);
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs;
#if HAS_FILE_SYSTEM_NAME
@ -51,6 +52,20 @@ namespace LibHac.FsSystem
return normalized;
}
public static Result Normalize(out U8Span normalizedPath, U8Span path)
{
if (path.Length == 0)
{
normalizedPath = path;
return Result.Success;
}
// Todo: optimize
normalizedPath = new U8Span(Normalize(path.ToString()));
return Result.Success;
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.