diff options
author | Mary <1760003+Thog@users.noreply.github.com> | 2021-07-13 16:48:54 +0200 |
---|---|---|
committer | Mary <1760003+Thog@users.noreply.github.com> | 2021-07-13 16:48:54 +0200 |
commit | 208ba1dde2b9a4d31446ace2bba8f0d641d2e300 (patch) | |
tree | c7478e7eb87061400bab37daf4f2f69cf387d9f2 /Ryujinx.HLE/FileSystem/VirtualFileSystem.cs | |
parent | 997380d48cb3b74e2438cee7fc3b017d6b59b714 (diff) |
Revert LibHac update
Users are facing save destruction on failing extra data update apparently
Diffstat (limited to 'Ryujinx.HLE/FileSystem/VirtualFileSystem.cs')
-rw-r--r-- | Ryujinx.HLE/FileSystem/VirtualFileSystem.cs | 345 |
1 files changed, 54 insertions, 291 deletions
diff --git a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index fbedd8d4..ff3232c2 100644 --- a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -1,23 +1,15 @@ using LibHac; using LibHac.Common; -using LibHac.Common.Keys; using LibHac.Fs; using LibHac.Fs.Fsa; -using LibHac.Fs.Shim; using LibHac.FsSrv; using LibHac.FsSystem; -using LibHac.Ncm; using LibHac.Spl; using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS; using System; -using System.Buffers.Text; -using System.Collections.Generic; using System.IO; -using System.Runtime.CompilerServices; -using RightsId = LibHac.Fs.RightsId; namespace Ryujinx.HLE.FileSystem { @@ -32,15 +24,17 @@ namespace Ryujinx.HLE.FileSystem private static bool _isInitialized = false; - public KeySet KeySet { get; private set; } + public Keyset KeySet { get; private set; } + public FileSystemServer FsServer { get; private set; } + public FileSystemClient FsClient { get; private set; } public EmulatedGameCard GameCard { get; private set; } public EmulatedSdCard SdCard { get; private set; } - public ModLoader ModLoader { get; private set; } + public ModLoader ModLoader {get; private set;} private VirtualFileSystem() { - ReloadKeySet(); + Reload(); ModLoader = new ModLoader(); // Should only be created once } @@ -86,6 +80,39 @@ namespace Ryujinx.HLE.FileSystem internal string GetSdCardPath() => MakeFullPath(SdCardPath); public string GetNandPath() => MakeFullPath(NandPath); + internal string GetSavePath(ServiceCtx context, SaveInfo saveInfo, bool isDirectory = true) + { + string saveUserPath = ""; + string baseSavePath = NandPath; + ulong currentTitleId = saveInfo.TitleId; + + switch (saveInfo.SaveSpaceId) + { + case SaveSpaceId.NandUser: baseSavePath = UserNandPath; break; + case SaveSpaceId.NandSystem: baseSavePath = SystemNandPath; break; + case SaveSpaceId.SdCard: baseSavePath = Path.Combine(SdCardPath, "Nintendo"); break; + } + + baseSavePath = Path.Combine(baseSavePath, "save"); + + if (saveInfo.TitleId == 0 && saveInfo.SaveDataType == SaveDataType.SaveData) + { + currentTitleId = context.Process.TitleId; + } + + if (saveInfo.SaveSpaceId == SaveSpaceId.NandUser) + { + saveUserPath = saveInfo.UserId.IsNull ? "savecommon" : saveInfo.UserId.ToString(); + } + + string savePath = Path.Combine(baseSavePath, + saveInfo.SaveId.ToString("x16"), + saveUserPath, + saveInfo.SaveDataType == SaveDataType.SaveData ? currentTitleId.ToString("x16") : string.Empty); + + return MakeFullPath(savePath, isDirectory); + } + public string GetFullPartitionPath(string partitionPath) { return MakeFullPath(partitionPath); @@ -109,8 +136,8 @@ namespace Ryujinx.HLE.FileSystem if (systemPath.StartsWith(baseSystemPath)) { - string rawPath = systemPath.Replace(baseSystemPath, ""); - int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar); + string rawPath = systemPath.Replace(baseSystemPath, ""); + int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar); if (firstSeparatorOffset == -1) { @@ -169,34 +196,33 @@ namespace Ryujinx.HLE.FileSystem return new DriveInfo(Path.GetPathRoot(GetBasePath())); } - public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient) + public void Reload() { - LocalFileSystem serverBaseFs = new LocalFileSystem(GetBasePath()); + ReloadKeySet(); - fsServerClient = horizon.CreatePrivilegedHorizonClient(); - var fsServer = new FileSystemServer(fsServerClient); + LocalFileSystem serverBaseFs = new LocalFileSystem(GetBasePath()); - DefaultFsServerObjects fsServerObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(serverBaseFs, KeySet, fsServer); + DefaultFsServerObjects fsServerObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(serverBaseFs, KeySet); GameCard = fsServerObjects.GameCard; - SdCard = fsServerObjects.SdCard; + SdCard = fsServerObjects.SdCard; SdCard.SetSdCardInsertionStatus(true); - var fsServerConfig = new FileSystemServerConfig + FileSystemServerConfig fsServerConfig = new FileSystemServerConfig { + FsCreators = fsServerObjects.FsCreators, DeviceOperator = fsServerObjects.DeviceOperator, - ExternalKeySet = KeySet.ExternalKeySet, - FsCreators = fsServerObjects.FsCreators + ExternalKeySet = KeySet.ExternalKeySet }; - FileSystemServerInitializer.InitializeWithConfig(fsServerClient, fsServer, fsServerConfig); + FsServer = new FileSystemServer(fsServerConfig); + FsClient = FsServer.CreateFileSystemClient(); } - public void ReloadKeySet() - { - KeySet ??= KeySet.CreateDefaultKeySet(); + private void ReloadKeySet() + { string keyFile = null; string titleKeyFile = null; string consoleKeyFile = null; @@ -230,7 +256,7 @@ namespace Ryujinx.HLE.FileSystem } } - ExternalKeyReader.ReadKeyFile(KeySet, keyFile, titleKeyFile, consoleKeyFile, null); + KeySet = ExternalKeyReader.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile); } public void ImportTickets(IFileSystem fs) @@ -251,269 +277,6 @@ namespace Ryujinx.HLE.FileSystem } } - // Save data created before we supported extra data in directory save data will not work properly if - // given empty extra data. Luckily some of that extra data can be created using the data from the - // save data indexer, which should be enough to check access permissions for user saves. - // Every single save data's extra data will be checked and fixed if needed each time the emulator is opened. - // Consider removing this at some point in the future when we don't need to worry about old saves. - public static Result FixExtraData(HorizonClient hos) - { - Result rc = GetSystemSaveList(hos, out List<ulong> systemSaveIds); - if (rc.IsFailure()) return rc; - - rc = FixUnindexedSystemSaves(hos, systemSaveIds); - if (rc.IsFailure()) return rc; - - rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.System); - if (rc.IsFailure()) return rc; - - rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.User); - if (rc.IsFailure()) return rc; - - rc = FixExtraDataInSpaceId(hos, SaveDataSpaceId.SdCache); - if (rc.IsFailure()) return rc; - - return Result.Success; - } - - private static Result FixExtraDataInSpaceId(HorizonClient hos, SaveDataSpaceId spaceId) - { - Span<SaveDataInfo> info = stackalloc SaveDataInfo[8]; - - Result rc = hos.Fs.OpenSaveDataIterator(out var iterator, spaceId); - if (rc.IsFailure()) return rc; - - while (true) - { - rc = iterator.ReadSaveDataInfo(out long count, info); - if (rc.IsFailure()) return rc; - - if (count == 0) - return Result.Success; - - for (int i = 0; i < count; i++) - { - rc = FixExtraData(out bool wasFixNeeded, hos, in info[i]); - - if (rc.IsFailure()) - { - Logger.Warning?.Print(LogClass.Application, $"Error {rc.ToStringWithName()} when fixing extra data for save data 0x{info[i].SaveDataId:x} in the {spaceId} save data space"); - } - else if (wasFixNeeded) - { - Logger.Info?.Print(LogClass.Application, $"Tried to rebuild extra data for save data 0x{info[i].SaveDataId:x} in the {spaceId} save data space"); - } - } - } - } - - // Gets a list of all the save data files or directories in the system partition. - private static Result GetSystemSaveList(HorizonClient hos, out List<ulong> list) - { - list = null; - - var mountName = "system".ToU8Span(); - DirectoryHandle handle = default; - List<ulong> localList = new List<ulong>(); - - try - { - Result rc = hos.Fs.MountBis(mountName, BisPartitionId.System); - if (rc.IsFailure()) return rc; - - rc = hos.Fs.OpenDirectory(out handle, "system:/save".ToU8Span(), OpenDirectoryMode.All); - if (rc.IsFailure()) return rc; - - DirectoryEntry entry = new DirectoryEntry(); - - while (true) - { - rc = hos.Fs.ReadDirectory(out long readCount, SpanHelpers.AsSpan(ref entry), handle); - if (rc.IsFailure()) return rc; - - if (readCount == 0) - break; - - if (Utf8Parser.TryParse(entry.Name, out ulong saveDataId, out int bytesRead, 'x') && - bytesRead == 16 && (long)saveDataId < 0) - { - localList.Add(saveDataId); - } - } - - list = localList; - - return Result.Success; - } - finally - { - if (handle.IsValid) - { - hos.Fs.CloseDirectory(handle); - } - - if (hos.Fs.IsMounted(mountName)) - { - hos.Fs.Unmount(mountName); - } - } - } - - // Adds system save data that isn't in the save data indexer to the indexer and creates extra data for it. - // Only save data IDs added to SystemExtraDataFixInfo will be fixed. - private static Result FixUnindexedSystemSaves(HorizonClient hos, List<ulong> existingSaveIds) - { - foreach (var fixInfo in SystemExtraDataFixInfo) - { - if (!existingSaveIds.Contains(fixInfo.StaticSaveDataId)) - { - continue; - } - - Result rc = FixSystemExtraData(out bool wasFixNeeded, hos, in fixInfo); - - if (rc.IsFailure()) - { - Logger.Warning?.Print(LogClass.Application, - $"Error {rc.ToStringWithName()} when fixing extra data for system save data 0x{fixInfo.StaticSaveDataId:x}"); - } - else if (wasFixNeeded) - { - Logger.Info?.Print(LogClass.Application, - $"Tried to rebuild extra data for system save data 0x{fixInfo.StaticSaveDataId:x}"); - } - } - - return Result.Success; - } - - private static Result FixSystemExtraData(out bool wasFixNeeded, HorizonClient hos, in ExtraDataFixInfo info) - { - wasFixNeeded = true; - - Result rc = hos.Fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, info.StaticSaveDataId); - if (!rc.IsSuccess()) - { - if (!ResultFs.TargetNotFound.Includes(rc)) - return rc; - - // We'll reach this point only if the save data directory exists but it's not in the save data indexer. - // Creating the save will add it to the indexer while leaving its existing contents intact. - return hos.Fs.CreateSystemSaveData(info.StaticSaveDataId, UserId.InvalidId, info.OwnerId, info.DataSize, - info.JournalSize, info.Flags); - } - - if (extraData.Attribute.StaticSaveDataId != 0 && extraData.OwnerId != 0) - { - wasFixNeeded = false; - return Result.Success; - } - - extraData = new SaveDataExtraData - { - Attribute = { StaticSaveDataId = info.StaticSaveDataId }, - OwnerId = info.OwnerId, - Flags = info.Flags, - DataSize = info.DataSize, - JournalSize = info.JournalSize - }; - - // Make a mask for writing the entire extra data - Unsafe.SkipInit(out SaveDataExtraData extraDataMask); - SpanHelpers.AsByteSpan(ref extraDataMask).Fill(0xFF); - - return hos.Fs.Impl.WriteSaveDataFileSystemExtraData(SaveDataSpaceId.System, info.StaticSaveDataId, - in extraData, in extraDataMask); - } - - private static Result FixExtraData(out bool wasFixNeeded, HorizonClient hos, in SaveDataInfo info) - { - wasFixNeeded = true; - - Result rc = hos.Fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, info.SpaceId, - info.SaveDataId); - if (rc.IsFailure()) return rc; - - // The extra data should have program ID or static save data ID set if it's valid. - // We only try to fix the extra data if the info from the save data indexer has a program ID or static save data ID. - bool canFixByProgramId = extraData.Attribute.ProgramId == ProgramId.InvalidId && - info.ProgramId != ProgramId.InvalidId; - - bool canFixBySaveDataId = extraData.Attribute.StaticSaveDataId == 0 && info.StaticSaveDataId != 0; - - if (!canFixByProgramId && !canFixBySaveDataId) - { - wasFixNeeded = false; - return Result.Success; - } - - // The save data attribute struct can be completely created from the save data info. - extraData.Attribute.ProgramId = info.ProgramId; - extraData.Attribute.UserId = info.UserId; - extraData.Attribute.StaticSaveDataId = info.StaticSaveDataId; - extraData.Attribute.Type = info.Type; - extraData.Attribute.Rank = info.Rank; - extraData.Attribute.Index = info.Index; - - // The rest of the extra data can't be created from the save data info. - // On user saves the owner ID will almost certainly be the same as the program ID. - if (info.Type != LibHac.Fs.SaveDataType.System) - { - extraData.OwnerId = info.ProgramId.Value; - } - else - { - // Try to match the system save with one of the known saves - foreach (ExtraDataFixInfo fixInfo in SystemExtraDataFixInfo) - { - if (extraData.Attribute.StaticSaveDataId == fixInfo.StaticSaveDataId) - { - extraData.OwnerId = fixInfo.OwnerId; - extraData.Flags = fixInfo.Flags; - extraData.DataSize = fixInfo.DataSize; - extraData.JournalSize = fixInfo.JournalSize; - - break; - } - } - } - - // Make a mask for writing the entire extra data - Unsafe.SkipInit(out SaveDataExtraData extraDataMask); - SpanHelpers.AsByteSpan(ref extraDataMask).Fill(0xFF); - - return hos.Fs.Impl.WriteSaveDataFileSystemExtraData(info.SpaceId, info.SaveDataId, in extraData, in extraDataMask); - } - - struct ExtraDataFixInfo - { - public ulong StaticSaveDataId; - public ulong OwnerId; - public SaveDataFlags Flags; - public long DataSize; - public long JournalSize; - } - - private static readonly ExtraDataFixInfo[] SystemExtraDataFixInfo = - { - new ExtraDataFixInfo() - { - StaticSaveDataId = 0x8000000000000030, - OwnerId = 0x010000000000001F, - Flags = SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData, - DataSize = 0x10000, - JournalSize = 0x10000 - }, - new ExtraDataFixInfo() - { - StaticSaveDataId = 0x8000000000001040, - OwnerId = 0x0100000000001009, - Flags = SaveDataFlags.None, - DataSize = 0xC000, - JournalSize = 0xC000 - } - }; - public void Unload() { RomFs?.Dispose(); @@ -536,7 +299,7 @@ namespace Ryujinx.HLE.FileSystem { if (_isInitialized) { - throw new InvalidOperationException("VirtualFileSystem can only be instantiated once!"); + throw new InvalidOperationException($"VirtualFileSystem can only be instantiated once!"); } _isInitialized = true; |