diff --git a/src/LibHac/Fs/PathTools.cs b/src/LibHac/Fs/PathTools.cs index 97dc2a76..538bd218 100644 --- a/src/LibHac/Fs/PathTools.cs +++ b/src/LibHac/Fs/PathTools.cs @@ -13,6 +13,7 @@ namespace LibHac.Fs public static readonly char DirectorySeparator = '/'; public static readonly char MountSeparator = ':'; internal const int MountNameLength = 0xF; + internal const int MaxPathLength = 0x300; public static string Normalize(string inPath) { diff --git a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs index 4cd3b224..335d65e2 100644 --- a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs @@ -13,6 +13,6 @@ namespace LibHac.FsService.Creators IFileSystem sourceFileSystem, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac, SaveDataType type, ITimeStampGenerator timeStampGenerator); - Result SetSdCardEncryptionSeed(ReadOnlySpan seed); + void SetSdCardEncryptionSeed(ReadOnlySpan seed); } } diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs new file mode 100644 index 00000000..0b7baf0e --- /dev/null +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -0,0 +1,93 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService +{ + public class FileSystemProxy + { + private FileSystemProxyCore FsProxyCore { get; } + public long CurrentProcess { get; private set; } + + public long SaveDataSize { get; private set; } + public long SaveDataJournalSize { get; private set; } + public string SaveDataRootPath { get; private set; } + public bool AutoCreateSaveData { get; private set; } + + public Result SetCurrentProcess(long processId) + { + CurrentProcess = processId; + + return Result.Success; + } + + public Result DisableAutoSaveDataCreation() + { + AutoCreateSaveData = false; + + return Result.Success; + } + + 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(string path) + { + // Missing permission check + + if (path.Length > PathTools.MaxPathLength) + { + return ResultFs.TooLongPath; + } + + SaveDataRootPath = path; + + return Result.Success; + } + + public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenBisFileSystem(out fileSystem, rootPath, partitionId); + } + + public Result OpenSdCardFileSystem(out IFileSystem fileSystem) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenSdCardFileSystem(out fileSystem); + } + + 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 SetSdCardEncryptionSeed(ReadOnlySpan seed) + { + // todo: use struct instead of byte span + if (seed.Length != 0x16) return ResultFs.InvalidSize; + + // Missing permission check + + Result res = FsProxyCore.SetSdCardEncryptionSeed(seed); + if (res.IsFailure()) return res; + + // todo: Reset save data indexer + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs new file mode 100644 index 00000000..25c486c0 --- /dev/null +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -0,0 +1,85 @@ +using System; +using LibHac.Fs; +using LibHac.FsService.Creators; + +namespace LibHac.FsService +{ + public class FileSystemProxyCore + { + private FileSystemCreators FsCreators { get; } + private byte[] SdEncryptionSeed { get; } = new byte[0x10]; + + private const string NintendoDirectoryName = "Nintendo"; + private const string ContentDirectoryName = "Contents"; + + public FileSystemProxyCore(FileSystemCreators fsCreators) + { + FsCreators = fsCreators; + } + + public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) + { + return FsCreators.BuiltInStorageFileSystemCreator.Create(out fileSystem, rootPath, partitionId); + } + + public Result OpenSdCardFileSystem(out IFileSystem fileSystem) + { + return FsCreators.SdFileSystemCreator.Create(out fileSystem); + } + + public Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId) + { + fileSystem = default; + + string contentDirPath = default; + IFileSystem baseFileSystem = default; + bool isEncrypted = false; + Result baseFsResult; + + switch (storageId) + { + case ContentStorageId.System: + baseFsResult = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.System); + contentDirPath = $"/{ContentDirectoryName}"; + break; + case ContentStorageId.User: + baseFsResult = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.User); + contentDirPath = $"/{ContentDirectoryName}"; + break; + case ContentStorageId.SdCard: + baseFsResult = OpenSdCardFileSystem(out baseFileSystem); + contentDirPath = $"/{NintendoDirectoryName}/{ContentDirectoryName}"; + isEncrypted = true; + break; + default: + baseFsResult = ResultFs.InvalidArgument; + break; + } + + if (baseFsResult.IsFailure()) return baseFsResult; + + baseFileSystem.EnsureDirectoryExists(contentDirPath); + + Result subFsResult = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFileSystem, + baseFileSystem, contentDirPath); + if (subFsResult.IsFailure()) return subFsResult; + + if (!isEncrypted) + { + fileSystem = subDirFileSystem; + return Result.Success; + } + + return FsCreators.EncryptedFileSystemCreator.Create(out fileSystem, subDirFileSystem, + EncryptedFsKeyId.Content, SdEncryptionSeed); + } + + public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) + { + seed.CopyTo(SdEncryptionSeed); + FsCreators.SaveDataFileSystemCreator.SetSdCardEncryptionSeed(seed); + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/FileSystemService.cs b/src/LibHac/FsService/FileSystemService.cs new file mode 100644 index 00000000..121cd31e --- /dev/null +++ b/src/LibHac/FsService/FileSystemService.cs @@ -0,0 +1,6 @@ +namespace LibHac.FsService +{ + public class FileSystemService + { + } +}