From cb705c5f0fca18ab4cf763bcdbb248076edac843 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 25 Aug 2019 21:41:48 -0500 Subject: [PATCH] Add some file system creators --- .../Creators/EmulatedBisFileSystemCreator.cs | 99 +++++++++++++++++++ .../EmulatedBisFileSystemCreatorConfig.cs | 73 ++++++++++++++ .../Creators/EmulatedSdFileSystemCreator.cs | 46 +++++++++ .../Creators/EncryptedFileSystemCreator.cs | 33 +++++++ .../FsService/Creators/FileSystemCreators.cs | 16 ++- .../Creators/SubDirectoryFileSystemCreator.cs | 25 +++++ src/LibHac/FsService/FileSystemProxy.cs | 11 +++ src/LibHac/FsService/FileSystemService.cs | 15 ++- src/LibHac/FsService/Util.cs | 47 +++++++++ 9 files changed, 363 insertions(+), 2 deletions(-) create mode 100644 src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs create mode 100644 src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Util.cs diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs new file mode 100644 index 00000000..3f9c4d99 --- /dev/null +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs @@ -0,0 +1,99 @@ +using System.Diagnostics; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class EmulatedBisFileSystemCreator : IBuiltInStorageFileSystemCreator + { + private EmulatedBisFileSystemCreatorConfig Config { get; } + + public EmulatedBisFileSystemCreator(IFileSystem rootFileSystem) + { + Config = new EmulatedBisFileSystemCreatorConfig(); + Config.RootFileSystem = rootFileSystem; + } + + public EmulatedBisFileSystemCreator(EmulatedBisFileSystemCreatorConfig config) + { + Config = config; + } + + public Result Create(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) + { + fileSystem = default; + + if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument; + if (rootPath == null) return ResultFs.NullArgument; + + if (Config.TryGetFileSystem(out fileSystem, partitionId)) + { + return Result.Success; + } + + if (Config.RootFileSystem == null) + { + return ResultFs.PreconditionViolation; + } + + string partitionPath = GetPartitionPath(partitionId); + + Result subFsResult = + Util.CreateSubFileSystem(out IFileSystem subFileSystem, Config.RootFileSystem, partitionPath, true); + + if (subFsResult.IsFailure()) return subFsResult; + + if (rootPath == string.Empty) + { + fileSystem = subFileSystem; + return Result.Success; + } + + return Util.CreateSubFileSystemImpl(out fileSystem, subFileSystem, rootPath); + } + + public Result CreateFatFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId) + { + fileSystem = default; + return ResultFs.NotImplemented; + } + + public Result SetBisRootForHost(BisPartitionId partitionId, string rootPath) + { + return Config.SetPath(rootPath, partitionId); + } + + private bool IsValidPartitionId(BisPartitionId id) + { + return id >= BisPartitionId.CalibrationFile && id <= BisPartitionId.System; + } + + private string GetPartitionPath(BisPartitionId id) + { + if (Config.TryGetPartitionPath(out string path, id)) + { + return path; + } + + return GetDefaultPartitionPath(id); + } + + private string GetDefaultPartitionPath(BisPartitionId id) + { + Debug.Assert(IsValidPartitionId(id)); + + switch (id) + { + case BisPartitionId.CalibrationFile: + return "/bis/cal"; + case BisPartitionId.SafeMode: + return "/bis/safe"; + case BisPartitionId.User: + return "/bis/user"; + case BisPartitionId.System: + return "/bis/system"; + default: + return string.Empty; + } + } + } +} diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs new file mode 100644 index 00000000..1e6ebe98 --- /dev/null +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs @@ -0,0 +1,73 @@ +using System.Diagnostics; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class EmulatedBisFileSystemCreatorConfig + { + private const int ValidPartitionCount = 4; + + public IFileSystem RootFileSystem { get; set; } + + private IFileSystem[] PartitionFileSystems { get; } = new IFileSystem[ValidPartitionCount]; + private string[] PartitionPaths { get; } = new string[ValidPartitionCount]; + + public Result SetFileSystem(IFileSystem fileSystem, BisPartitionId partitionId) + { + if (fileSystem == null) return ResultFs.NullArgument; + if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument; + + PartitionFileSystems[GetArrayIndex(partitionId)] = fileSystem; + + return Result.Success; + } + + public Result SetPath(string path, BisPartitionId partitionId) + { + if (path == null) return ResultFs.NullArgument; + if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument; + + PartitionPaths[GetArrayIndex(partitionId)] = path; + + return Result.Success; + } + + public bool TryGetFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId) + { + if (!IsValidPartitionId(partitionId)) + { + fileSystem = default; + return false; + } + + fileSystem = PartitionFileSystems[GetArrayIndex(partitionId)]; + + return fileSystem != null; + } + + public bool TryGetPartitionPath(out string path, BisPartitionId partitionId) + { + if (!IsValidPartitionId(partitionId)) + { + path = default; + return false; + } + + path = PartitionPaths[GetArrayIndex(partitionId)]; + + return path != null; + } + + private int GetArrayIndex(BisPartitionId id) + { + Debug.Assert(IsValidPartitionId(id)); + + return id - BisPartitionId.CalibrationFile; + } + + private bool IsValidPartitionId(BisPartitionId id) + { + return id >= BisPartitionId.CalibrationFile && id <= BisPartitionId.System; + } + } +} diff --git a/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs new file mode 100644 index 00000000..b27c6aff --- /dev/null +++ b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs @@ -0,0 +1,46 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + class EmulatedSdFileSystemCreator : ISdFileSystemCreator + { + private const string DefaultPath = "/sdcard"; + + public IFileSystem RootFileSystem { get; set; } + public string Path { get; set; } + + public IFileSystem SdCardFileSystem { get; set; } + + public EmulatedSdFileSystemCreator(IFileSystem rootFileSystem) + { + RootFileSystem = rootFileSystem; + } + + public Result Create(out IFileSystem fileSystem) + { + fileSystem = default; + + if (SdCardFileSystem != null) + { + fileSystem = SdCardFileSystem; + + return Result.Success; + } + + if (RootFileSystem == null) + { + return ResultFs.PreconditionViolation; + } + + string path = Path ?? DefaultPath; + + return Util.CreateSubFileSystem(out fileSystem, RootFileSystem, path, true); + } + + public Result Format(bool closeOpenEntries) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs b/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs new file mode 100644 index 00000000..81d5dc4b --- /dev/null +++ b/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs @@ -0,0 +1,33 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator + { + private Keyset Keyset { get; } + + public EncryptedFileSystemCreator(Keyset keyset) + { + Keyset = keyset; + } + + public Result Create(out IFileSystem encryptedFileSystem, IFileSystem baseFileSystem, EncryptedFsKeyId keyId, + ReadOnlySpan encryptionSeed) + { + encryptedFileSystem = default; + + if (keyId < EncryptedFsKeyId.Save || keyId > EncryptedFsKeyId.CustomStorage) + { + return ResultFs.InvalidArgument; + } + + // todo: "proper" key generation instead of a lazy hack + Keyset.SetSdSeed(encryptionSeed.ToArray()); + + encryptedFileSystem = new AesXtsFileSystem(baseFileSystem, Keyset.SdCardKeys[(int)keyId], 0x4000); + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs index f38d476c..2ae3114f 100644 --- a/src/LibHac/FsService/Creators/FileSystemCreators.cs +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -1,4 +1,6 @@ -namespace LibHac.FsService.Creators +using LibHac.Fs; + +namespace LibHac.FsService.Creators { public class FileSystemCreators { @@ -16,5 +18,17 @@ public IMemoryStorageCreator MemoryStorageCreator { get; set; } public IBuiltInStorageFileSystemCreator BuiltInStorageFileSystemCreator { get; set; } public ISdFileSystemCreator SdFileSystemCreator { get; set; } + + public static FileSystemCreators GetDefaultEmulatedCreators(IFileSystem rootFileSystem, Keyset keyset) + { + var creators = new FileSystemCreators(); + + creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); + creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keyset); + creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem); + creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(rootFileSystem); + + return creators; + } } } diff --git a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs new file mode 100644 index 00000000..526ffb4e --- /dev/null +++ b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs @@ -0,0 +1,25 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class SubDirectoryFileSystemCreator : ISubDirectoryFileSystemCreator + { + public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path) + { + try + { + baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directories); + } + catch (HorizonResultException ex) + { + subDirFileSystem = default; + + return ex.ResultValue; + } + + subDirFileSystem = new SubdirectoryFileSystem(baseFileSystem, path); + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 0b7baf0e..5d61e0be 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -13,6 +13,17 @@ namespace LibHac.FsService public string SaveDataRootPath { get; private set; } public bool AutoCreateSaveData { get; private set; } + internal FileSystemProxy(FileSystemProxyCore fsProxyCore) + { + FsProxyCore = fsProxyCore; + + CurrentProcess = -1; + SaveDataSize = 0x2000000; + SaveDataJournalSize = 0x1000000; + SaveDataRootPath = string.Empty; + AutoCreateSaveData = true; + } + public Result SetCurrentProcess(long processId) { CurrentProcess = processId; diff --git a/src/LibHac/FsService/FileSystemService.cs b/src/LibHac/FsService/FileSystemService.cs index 121cd31e..7597dd3e 100644 --- a/src/LibHac/FsService/FileSystemService.cs +++ b/src/LibHac/FsService/FileSystemService.cs @@ -1,6 +1,19 @@ -namespace LibHac.FsService +using LibHac.FsService.Creators; + +namespace LibHac.FsService { public class FileSystemService { + private FileSystemProxyCore FsProxyCore { get; } + + public FileSystemService(FileSystemCreators fsCreators) + { + FsProxyCore = new FileSystemProxyCore(fsCreators); + } + + public FileSystemProxy CreateFileSystemProxyService() + { + return new FileSystemProxy(FsProxyCore); + } } } diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs new file mode 100644 index 00000000..9ebcab9e --- /dev/null +++ b/src/LibHac/FsService/Util.cs @@ -0,0 +1,47 @@ +using LibHac.Fs; + +namespace LibHac.FsService +{ + public static class Util + { + public static Result CreateSubFileSystem(out IFileSystem subFileSystem, IFileSystem baseFileSystem, string path, + bool createPathIfMissing) + { + subFileSystem = default; + + if (!createPathIfMissing) + { + if (path == null) return ResultFs.NullArgument; + + if (baseFileSystem.GetEntryType(path) != DirectoryEntryType.Directory) + { + return ResultFs.PathNotFound; + } + } + + baseFileSystem.EnsureDirectoryExists(path); + + return CreateSubFileSystemImpl(out subFileSystem, baseFileSystem, path); + } + + public static Result CreateSubFileSystemImpl(out IFileSystem subFileSystem, IFileSystem baseFileSystem, string path) + { + subFileSystem = default; + + if (path == null) return ResultFs.NullArgument; + + try + { + baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directories); + } + catch (HorizonResultException ex) + { + return ex.ResultValue; + } + + subFileSystem = new SubdirectoryFileSystem(baseFileSystem, path); + + return Result.Success; + } + } +}