Add OpenSaveDataFileSystemBySystemSaveDataId

This commit is contained in:
Alex Barney 2019-08-29 18:54:51 -05:00
parent d610d2262b
commit d6165d1097
10 changed files with 248 additions and 2 deletions

View file

@ -33,6 +33,7 @@ namespace LibHac.Fs
}
else
{
// todo: FS returns invalid file entries with a size of 0
long size = GetAesXtsFileSize(entry.FullPath);
if (size == -1) continue;

View file

@ -42,4 +42,15 @@
Secure = 1,
Writable = 2
}
public enum SaveDataSpaceId
{
System = 0,
User = 1,
SdSystem = 2,
TemporaryStorage = 3,
SdCache = 4,
ProperSystem = 100,
Safe = 101
}
}

View file

@ -11,6 +11,9 @@
public static Result InsufficientFreeSpace => new Result(ModuleFs, 30);
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 Result3002 => new Result(ModuleFs, 3002);
public static Result SaveDataPathAlreadyExists => new Result(ModuleFs, 3003);

View file

@ -8,6 +8,8 @@ namespace LibHac.FsService.Creators
public IPartitionFileSystemCreator PartitionFileSystemCreator { get; set; }
public IStorageOnNcaCreator StorageOnNcaCreator { get; set; }
public IFatFileSystemCreator FatFileSystemCreator { get; set; }
public IHostFileSystemCreator HostFileSystemCreator { get; set; }
public ITargetManagerFileSystemCreator TargetManagerFileSystemCreator { get; set; }
public ISubDirectoryFileSystemCreator SubDirectoryFileSystemCreator { get; set; }
public IBuiltInStorageCreator BuiltInStorageCreator { get; set; }
public ISdStorageCreator SdStorageCreator { get; set; }

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

View file

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

View file

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsService
@ -13,6 +14,8 @@ namespace LibHac.FsService
public string SaveDataRootPath { get; private set; }
public bool AutoCreateSaveData { get; private set; }
private const ulong SaveIndexerId = 0x8000000000000000;
internal FileSystemProxy(FileSystemProxyCore fsProxyCore)
{
FsProxyCore = fsProxyCore;
@ -86,10 +89,29 @@ namespace LibHac.FsService
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)
{
// todo: use struct instead of byte span
if (seed.Length != 0x16) return ResultFs.InvalidSize;
if (seed.Length != 0x10) return ResultFs.InvalidSize;
// Missing permission check
@ -100,5 +122,42 @@ namespace LibHac.FsService
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;
}
}
}

View file

@ -1,5 +1,6 @@
using System;
using LibHac.Fs;
using LibHac.Fs.Save;
using LibHac.FsService.Creators;
namespace LibHac.FsService
@ -77,9 +78,129 @@ namespace LibHac.FsService
public Result SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed)
{
seed.CopyTo(SdEncryptionSeed);
FsCreators.SaveDataFileSystemCreator.SetSdCardEncryptionSeed(seed);
//FsCreators.SaveDataFileSystemCreator.SetSdCardEncryptionSeed(seed);
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}";
}
}
}

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

View file

@ -43,5 +43,14 @@ namespace LibHac.FsService
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;
}
}
}