Clean the SD card save directory when opening the emulator (#2564)

Cleans "sdcard:/Nintendo/save" and deletes "sdcard:/save" when opening the emulator.

Works around invalid encryption when keys or the SD card encryption seed are changed.
This commit is contained in:
Alex Barney 2021-08-20 13:36:14 -07:00 committed by GitHub
parent 97aedc030d
commit e0af248e6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 34 deletions

View file

@ -9,8 +9,6 @@ namespace Ryujinx.HLE.FileSystem
{ {
public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator
{ {
public EncryptedFileSystemCreator() { }
public Result Create(out ReferenceCountedDisposable<IFileSystem> encryptedFileSystem, ReferenceCountedDisposable<IFileSystem> baseFileSystem, public Result Create(out ReferenceCountedDisposable<IFileSystem> encryptedFileSystem, ReferenceCountedDisposable<IFileSystem> baseFileSystem,
EncryptedFsKeyId keyId, in EncryptionSeed encryptionSeed) EncryptedFsKeyId keyId, in EncryptionSeed encryptionSeed)
{ {
@ -23,40 +21,9 @@ namespace Ryujinx.HLE.FileSystem
// Force all-zero keys for now since people can open the emulator with different keys or sd seeds sometimes // Force all-zero keys for now since people can open the emulator with different keys or sd seeds sometimes
var fs = new AesXtsFileSystem(baseFileSystem, new byte[0x32], 0x4000); var fs = new AesXtsFileSystem(baseFileSystem, new byte[0x32], 0x4000);
var aesFileSystem = new ReferenceCountedDisposable<IFileSystem>(fs); encryptedFileSystem = new ReferenceCountedDisposable<IFileSystem>(fs);
// This wrapper will handle deleting files that were created with different keys
var wrappedFs = new ChangedEncryptionHandlingFileSystem(aesFileSystem);
encryptedFileSystem = new ReferenceCountedDisposable<IFileSystem>(wrappedFs);
return Result.Success; return Result.Success;
} }
} }
public class ChangedEncryptionHandlingFileSystem : ForwardingFileSystem
{
public ChangedEncryptionHandlingFileSystem(ReferenceCountedDisposable<IFileSystem> baseFileSystem) : base(baseFileSystem) { }
protected override Result DoOpenFile(out IFile file, U8Span path, OpenMode mode)
{
UnsafeHelpers.SkipParamInit(out file);
try
{
return base.DoOpenFile(out file, path, mode);
}
catch (HorizonResultException ex)
{
if (ResultFs.AesXtsFileHeaderInvalidKeys.Includes(ex.ResultValue))
{
Result rc = DeleteFile(path);
if (rc.IsFailure()) return rc;
return base.DoOpenFile(out file, path, mode);
}
throw;
}
}
}
} }

View file

@ -1,5 +1,8 @@
using LibHac; using LibHac;
using LibHac.Bcat; using LibHac.Bcat;
using LibHac.Common;
using LibHac.Fs.Fsa;
using LibHac.Fs.Shim;
using LibHac.FsSrv.Impl; using LibHac.FsSrv.Impl;
using LibHac.Loader; using LibHac.Loader;
using LibHac.Ncm; using LibHac.Ncm;
@ -57,6 +60,8 @@ namespace Ryujinx.HLE.HOS
virtualFileSystem.InitializeFsServer(Server, out var fsClient); virtualFileSystem.InitializeFsServer(Server, out var fsClient);
FsClient = fsClient; FsClient = fsClient;
CleanSdCardDirectory();
} }
public void InitializeSystemClients() public void InitializeSystemClients()
@ -80,6 +85,27 @@ namespace Ryujinx.HLE.HOS
npdm.FsAccessControlData, npdm.FsAccessControlDescriptor); npdm.FsAccessControlData, npdm.FsAccessControlDescriptor);
} }
// This function was added to avoid errors that come from a user's keys or SD encryption seed changing.
// Catching these errors and recreating the file ended up not working because of the different ways
// applications respond to a file suddenly containing all zeros or having a length of zero.
// Clearing the SD card save directory was determined to be the best option for the moment since
// the saves on the SD card are meant as caches that can be deleted at any time.
private void CleanSdCardDirectory()
{
Result rc = RyujinxClient.Fs.MountSdCard("sdcard".ToU8Span());
if (rc.IsFailure()) return;
try
{
RyujinxClient.Fs.CleanDirectoryRecursively("sdcard:/Nintendo/save".ToU8Span()).IgnoreResult();
RyujinxClient.Fs.DeleteDirectoryRecursively("sdcard:/save".ToU8Span()).IgnoreResult();
}
finally
{
RyujinxClient.Fs.Unmount("sdcard".ToU8Span());
}
}
private static AccessControlBits.Bits AccountFsPermissions => AccessControlBits.Bits.SystemSaveData | private static AccessControlBits.Bits AccountFsPermissions => AccessControlBits.Bits.SystemSaveData |
AccessControlBits.Bits.GameCard | AccessControlBits.Bits.GameCard |
AccessControlBits.Bits.SaveDataMeta | AccessControlBits.Bits.SaveDataMeta |