mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add OpenSaveDataFileSystemBySystemSaveDataId
This commit is contained in:
parent
d610d2262b
commit
d6165d1097
10 changed files with 248 additions and 2 deletions
|
@ -33,6 +33,7 @@ namespace LibHac.Fs
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// todo: FS returns invalid file entries with a size of 0
|
||||||
long size = GetAesXtsFileSize(entry.FullPath);
|
long size = GetAesXtsFileSize(entry.FullPath);
|
||||||
if (size == -1) continue;
|
if (size == -1) continue;
|
||||||
|
|
||||||
|
|
|
@ -42,4 +42,15 @@
|
||||||
Secure = 1,
|
Secure = 1,
|
||||||
Writable = 2
|
Writable = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum SaveDataSpaceId
|
||||||
|
{
|
||||||
|
System = 0,
|
||||||
|
User = 1,
|
||||||
|
SdSystem = 2,
|
||||||
|
TemporaryStorage = 3,
|
||||||
|
SdCache = 4,
|
||||||
|
ProperSystem = 100,
|
||||||
|
Safe = 101
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
public static Result InsufficientFreeSpace => new Result(ModuleFs, 30);
|
public static Result InsufficientFreeSpace => new Result(ModuleFs, 30);
|
||||||
public static Result MountNameAlreadyExists => new Result(ModuleFs, 60);
|
public static Result MountNameAlreadyExists => new Result(ModuleFs, 60);
|
||||||
|
|
||||||
|
public static Result ResultPartitionNotFound => new Result(ModuleFs, 1002);
|
||||||
|
public static Result TargetNotFound => new Result(ModuleFs, 1002);
|
||||||
|
|
||||||
public static Result NotImplemented => new Result(ModuleFs, 3001);
|
public static Result NotImplemented => new Result(ModuleFs, 3001);
|
||||||
public static Result Result3002 => new Result(ModuleFs, 3002);
|
public static Result Result3002 => new Result(ModuleFs, 3002);
|
||||||
public static Result SaveDataPathAlreadyExists => new Result(ModuleFs, 3003);
|
public static Result SaveDataPathAlreadyExists => new Result(ModuleFs, 3003);
|
||||||
|
|
|
@ -8,6 +8,8 @@ namespace LibHac.FsService.Creators
|
||||||
public IPartitionFileSystemCreator PartitionFileSystemCreator { get; set; }
|
public IPartitionFileSystemCreator PartitionFileSystemCreator { get; set; }
|
||||||
public IStorageOnNcaCreator StorageOnNcaCreator { get; set; }
|
public IStorageOnNcaCreator StorageOnNcaCreator { get; set; }
|
||||||
public IFatFileSystemCreator FatFileSystemCreator { get; set; }
|
public IFatFileSystemCreator FatFileSystemCreator { get; set; }
|
||||||
|
public IHostFileSystemCreator HostFileSystemCreator { get; set; }
|
||||||
|
public ITargetManagerFileSystemCreator TargetManagerFileSystemCreator { get; set; }
|
||||||
public ISubDirectoryFileSystemCreator SubDirectoryFileSystemCreator { get; set; }
|
public ISubDirectoryFileSystemCreator SubDirectoryFileSystemCreator { get; set; }
|
||||||
public IBuiltInStorageCreator BuiltInStorageCreator { get; set; }
|
public IBuiltInStorageCreator BuiltInStorageCreator { get; set; }
|
||||||
public ISdStorageCreator SdStorageCreator { get; set; }
|
public ISdStorageCreator SdStorageCreator { get; set; }
|
||||||
|
|
10
src/LibHac/FsService/Creators/IHostFileSystemCreator.cs
Normal file
10
src/LibHac/FsService/Creators/IHostFileSystemCreator.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using LibHac.Fs;
|
||||||
|
|
||||||
|
namespace LibHac.FsService.Creators
|
||||||
|
{
|
||||||
|
public interface IHostFileSystemCreator
|
||||||
|
{
|
||||||
|
Result Create(out IFileSystem fileSystem, bool someBool);
|
||||||
|
Result Create(out IFileSystem fileSystem, string path, bool someBool);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using LibHac.Fs;
|
||||||
|
|
||||||
|
namespace LibHac.FsService.Creators
|
||||||
|
{
|
||||||
|
public interface ITargetManagerFileSystemCreator
|
||||||
|
{
|
||||||
|
Result Create(out IFileSystem fileSystem, bool someBool);
|
||||||
|
Result GetCaseSensitivePath(out bool isSuccess, ref string path);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
|
||||||
namespace LibHac.FsService
|
namespace LibHac.FsService
|
||||||
|
@ -13,6 +14,8 @@ namespace LibHac.FsService
|
||||||
public string SaveDataRootPath { get; private set; }
|
public string SaveDataRootPath { get; private set; }
|
||||||
public bool AutoCreateSaveData { get; private set; }
|
public bool AutoCreateSaveData { get; private set; }
|
||||||
|
|
||||||
|
private const ulong SaveIndexerId = 0x8000000000000000;
|
||||||
|
|
||||||
internal FileSystemProxy(FileSystemProxyCore fsProxyCore)
|
internal FileSystemProxy(FileSystemProxyCore fsProxyCore)
|
||||||
{
|
{
|
||||||
FsProxyCore = fsProxyCore;
|
FsProxyCore = fsProxyCore;
|
||||||
|
@ -86,10 +89,29 @@ namespace LibHac.FsService
|
||||||
return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId);
|
return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId,
|
||||||
|
SaveDataAttribute attribute)
|
||||||
|
{
|
||||||
|
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
|
||||||
|
fileSystem = default;
|
||||||
|
|
||||||
|
if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
Result saveFsResult = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out ulong saveDataId, spaceId,
|
||||||
|
attribute, false, true);
|
||||||
|
if (saveFsResult.IsFailure()) return saveFsResult.Log();
|
||||||
|
|
||||||
|
// Missing check if the current title owns the save data or can open it
|
||||||
|
|
||||||
|
fileSystem = saveFs;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
public Result SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed)
|
public Result SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed)
|
||||||
{
|
{
|
||||||
// todo: use struct instead of byte span
|
// todo: use struct instead of byte span
|
||||||
if (seed.Length != 0x16) return ResultFs.InvalidSize;
|
if (seed.Length != 0x10) return ResultFs.InvalidSize;
|
||||||
|
|
||||||
// Missing permission check
|
// Missing permission check
|
||||||
|
|
||||||
|
@ -100,5 +122,42 @@ namespace LibHac.FsService
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Result OpenSaveDataFileSystemImpl(out IFileSystem fileSystem, out ulong saveDataId,
|
||||||
|
SaveDataSpaceId spaceId, SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData)
|
||||||
|
{
|
||||||
|
bool hasFixedId = attribute.SaveId != 0 && attribute.UserId.Id == Id128.InvalidId;
|
||||||
|
|
||||||
|
if (hasFixedId)
|
||||||
|
{
|
||||||
|
saveDataId = attribute.SaveId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result saveFsResult = FsProxyCore.OpenSaveDataFileSystem(out fileSystem, spaceId, saveDataId,
|
||||||
|
SaveDataRootPath, openReadOnly, attribute.Type, cacheExtraData);
|
||||||
|
|
||||||
|
if (saveFsResult.IsSuccess()) return Result.Success;
|
||||||
|
|
||||||
|
if (saveFsResult == ResultFs.PathNotFound || saveFsResult == ResultFs.TargetNotFound) return saveFsResult;
|
||||||
|
|
||||||
|
if (saveDataId != SaveIndexerId)
|
||||||
|
{
|
||||||
|
if(hasFixedId)
|
||||||
|
{
|
||||||
|
// todo: remove save indexer entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultFs.TargetNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsSystemSaveDataId(ulong id)
|
||||||
|
{
|
||||||
|
return (long)id < 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Save;
|
||||||
using LibHac.FsService.Creators;
|
using LibHac.FsService.Creators;
|
||||||
|
|
||||||
namespace LibHac.FsService
|
namespace LibHac.FsService
|
||||||
|
@ -77,9 +78,129 @@ namespace LibHac.FsService
|
||||||
public Result SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed)
|
public Result SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed)
|
||||||
{
|
{
|
||||||
seed.CopyTo(SdEncryptionSeed);
|
seed.CopyTo(SdEncryptionSeed);
|
||||||
FsCreators.SaveDataFileSystemCreator.SetSdCardEncryptionSeed(seed);
|
//FsCreators.SaveDataFileSystemCreator.SetSdCardEncryptionSeed(seed);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AllowDirectorySaveData(SaveDataSpaceId spaceId, string saveDataRootPath)
|
||||||
|
{
|
||||||
|
return spaceId == SaveDataSpaceId.User && !string.IsNullOrWhiteSpace(saveDataRootPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId,
|
||||||
|
string saveDataRootPath, bool openReadOnly, SaveDataType type, bool cacheExtraData)
|
||||||
|
{
|
||||||
|
fileSystem = default;
|
||||||
|
|
||||||
|
Result openSaveDirResult = OpenSaveDataDirectory(out IFileSystem saveDirFs, spaceId, saveDataRootPath, true);
|
||||||
|
if (openSaveDirResult.IsFailure()) return openSaveDirResult.Log();
|
||||||
|
|
||||||
|
bool allowDirectorySaveData = AllowDirectorySaveData(spaceId, saveDataRootPath);
|
||||||
|
bool useDeviceUniqueMac = Util.UseDeviceUniqueSaveMac(spaceId);
|
||||||
|
|
||||||
|
if (allowDirectorySaveData)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
saveDirFs.EnsureDirectoryExists(GetSaveDataIdPath(saveDataId));
|
||||||
|
}
|
||||||
|
catch (HorizonResultException ex)
|
||||||
|
{
|
||||||
|
return ex.ResultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Missing save FS cache lookup
|
||||||
|
|
||||||
|
Result saveFsResult = FsCreators.SaveDataFileSystemCreator.Create(out IFileSystem saveFs,
|
||||||
|
out ISaveDataExtraDataAccessor extraDataAccessor, saveDirFs, saveDataId, allowDirectorySaveData,
|
||||||
|
useDeviceUniqueMac, type, null);
|
||||||
|
|
||||||
|
if (saveFsResult.IsFailure()) return saveFsResult.Log();
|
||||||
|
|
||||||
|
if (cacheExtraData)
|
||||||
|
{
|
||||||
|
// Missing extra data caching
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSystem = openReadOnly ? new ReadOnlyFileSystem(saveFs) : saveFs;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenSaveDataDirectory(out IFileSystem fileSystem, SaveDataSpaceId spaceId, string saveDataRootPath, bool openOnHostFs)
|
||||||
|
{
|
||||||
|
if (openOnHostFs && AllowDirectorySaveData(spaceId, saveDataRootPath))
|
||||||
|
{
|
||||||
|
Result hostFsResult = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, false);
|
||||||
|
|
||||||
|
if (hostFsResult.IsFailure())
|
||||||
|
{
|
||||||
|
fileSystem = default;
|
||||||
|
return hostFsResult.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Util.CreateSubFileSystem(out fileSystem, hostFs, saveDataRootPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
string dirName = spaceId == SaveDataSpaceId.TemporaryStorage ? "/temp" : "/save";
|
||||||
|
|
||||||
|
return OpenSaveDataDirectoryImpl(out fileSystem, spaceId, dirName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result OpenSaveDataDirectoryImpl(out IFileSystem fileSystem, SaveDataSpaceId spaceId, string saveDirName, bool createIfMissing)
|
||||||
|
{
|
||||||
|
fileSystem = default;
|
||||||
|
|
||||||
|
switch (spaceId)
|
||||||
|
{
|
||||||
|
case SaveDataSpaceId.System:
|
||||||
|
Result sysFsResult = OpenBisFileSystem(out IFileSystem sysFs, string.Empty, BisPartitionId.System);
|
||||||
|
if (sysFsResult.IsFailure()) return sysFsResult.Log();
|
||||||
|
|
||||||
|
return Util.CreateSubFileSystem(out fileSystem, sysFs, saveDirName, createIfMissing);
|
||||||
|
|
||||||
|
case SaveDataSpaceId.User:
|
||||||
|
case SaveDataSpaceId.TemporaryStorage:
|
||||||
|
Result userFsResult = OpenBisFileSystem(out IFileSystem userFs, string.Empty, BisPartitionId.System);
|
||||||
|
if (userFsResult.IsFailure()) return userFsResult.Log();
|
||||||
|
|
||||||
|
return Util.CreateSubFileSystem(out fileSystem, userFs, saveDirName, createIfMissing);
|
||||||
|
|
||||||
|
case SaveDataSpaceId.SdSystem:
|
||||||
|
case SaveDataSpaceId.SdCache:
|
||||||
|
Result sdFsResult = OpenSdCardFileSystem(out IFileSystem sdFs);
|
||||||
|
if (sdFsResult.IsFailure()) return sdFsResult.Log();
|
||||||
|
|
||||||
|
string sdSaveDirPath = $"/{NintendoDirectoryName}{saveDirName}";
|
||||||
|
|
||||||
|
Result sdSubResult = Util.CreateSubFileSystem(out IFileSystem sdSubFs, sdFs, sdSaveDirPath, createIfMissing);
|
||||||
|
if (sdSubResult.IsFailure()) return sdSubResult.Log();
|
||||||
|
|
||||||
|
return FsCreators.EncryptedFileSystemCreator.Create(out fileSystem, sdSubFs,
|
||||||
|
EncryptedFsKeyId.Save, SdEncryptionSeed);
|
||||||
|
|
||||||
|
case SaveDataSpaceId.ProperSystem:
|
||||||
|
Result sysProperFsResult = OpenBisFileSystem(out IFileSystem sysProperFs, string.Empty, BisPartitionId.SystemProperPartition);
|
||||||
|
if (sysProperFsResult.IsFailure()) return sysProperFsResult.Log();
|
||||||
|
|
||||||
|
return Util.CreateSubFileSystem(out fileSystem, sysProperFs, saveDirName, createIfMissing);
|
||||||
|
|
||||||
|
case SaveDataSpaceId.Safe:
|
||||||
|
Result safeFsResult = OpenBisFileSystem(out IFileSystem safeFs, string.Empty, BisPartitionId.SafeMode);
|
||||||
|
if (safeFsResult.IsFailure()) return safeFsResult.Log();
|
||||||
|
|
||||||
|
return Util.CreateSubFileSystem(out fileSystem, safeFs, saveDirName, createIfMissing);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetSaveDataIdPath(ulong saveDataId)
|
||||||
|
{
|
||||||
|
return $"/{saveDataId:x16}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
src/LibHac/FsService/IFileSystemProxy.cs
Normal file
20
src/LibHac/FsService/IFileSystemProxy.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using LibHac.Fs;
|
||||||
|
|
||||||
|
namespace LibHac.FsService
|
||||||
|
{
|
||||||
|
public interface IFileSystemProxy
|
||||||
|
{
|
||||||
|
Result SetCurrentProcess(long processId);
|
||||||
|
Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId);
|
||||||
|
Result OpenSdCardFileSystem(out IFileSystem fileSystem);
|
||||||
|
Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId);
|
||||||
|
Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute);
|
||||||
|
Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute);
|
||||||
|
Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId);
|
||||||
|
Result SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed);
|
||||||
|
Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize);
|
||||||
|
Result SetSaveDataRootPath(string path);
|
||||||
|
Result DisableAutoSaveDataCreation();
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,5 +43,14 @@ namespace LibHac.FsService
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool UseDeviceUniqueSaveMac(SaveDataSpaceId spaceId)
|
||||||
|
{
|
||||||
|
return spaceId == SaveDataSpaceId.System ||
|
||||||
|
spaceId == SaveDataSpaceId.User ||
|
||||||
|
spaceId == SaveDataSpaceId.TemporaryStorage ||
|
||||||
|
spaceId == SaveDataSpaceId.ProperSystem ||
|
||||||
|
spaceId == SaveDataSpaceId.Safe;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue