Add some file system creators

This commit is contained in:
Alex Barney 2019-08-25 21:41:48 -05:00
parent 82c5c5d9a0
commit cb705c5f0f
9 changed files with 363 additions and 2 deletions

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}
}

View file

@ -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<byte> 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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}