diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/file_sys/fs_save_data_types.h | 174 | ||||
-rw-r--r-- | src/core/file_sys/savedata_factory.cpp | 90 | ||||
-rw-r--r-- | src/core/file_sys/savedata_factory.h | 68 |
3 files changed, 197 insertions, 135 deletions
diff --git a/src/core/file_sys/fs_save_data_types.h b/src/core/file_sys/fs_save_data_types.h new file mode 100644 index 000000000..02bbc3294 --- /dev/null +++ b/src/core/file_sys/fs_save_data_types.h @@ -0,0 +1,174 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace FileSys { + +using SaveDataId = u64; +using SystemSaveDataId = u64; +using SystemBcatSaveDataId = SystemSaveDataId; +using ProgramId = u64; + +enum class SaveDataSpaceId : u8 { + System = 0, + User = 1, + SdSystem = 2, + Temporary = 3, + SdUser = 4, + + ProperSystem = 100, + SafeMode = 101, +}; + +enum class SaveDataType : u8 { + System = 0, + Account = 1, + Bcat = 2, + Device = 3, + Temporary = 4, + Cache = 5, + SystemBcat = 6, +}; + +enum class SaveDataRank : u8 { + Primary = 0, + Secondary = 1, +}; + +struct SaveDataSize { + u64 normal; + u64 journal; +}; +static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size."); + +using UserId = u128; +static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable."); +static_assert(sizeof(UserId) == 0x10, "UserId has invalid size."); + +constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0; +constexpr inline UserId InvalidUserId = {}; + +enum class SaveDataFlags : u32 { + None = (0 << 0), + KeepAfterResettingSystemSaveData = (1 << 0), + KeepAfterRefurbishment = (1 << 1), + KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2), + NeedsSecureDelete = (1 << 3), +}; + +enum class SaveDataMetaType : u8 { + None = 0, + Thumbnail = 1, + ExtensionContext = 2, +}; + +struct SaveDataMetaInfo { + u32 size; + SaveDataMetaType type; + INSERT_PADDING_BYTES(0xB); +}; +static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>, + "Data type must be trivially copyable."); +static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size."); + +struct SaveDataCreationInfo { + s64 size; + s64 journal_size; + s64 block_size; + u64 owner_id; + u32 flags; + SaveDataSpaceId space_id; + bool pseudo; + INSERT_PADDING_BYTES(0x1A); +}; +static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>, + "Data type must be trivially copyable."); +static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size."); + +struct SaveDataAttribute { + ProgramId program_id; + UserId user_id; + SystemSaveDataId system_save_data_id; + SaveDataType type; + SaveDataRank rank; + u16 index; + INSERT_PADDING_BYTES(0x1C); + + static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id, + SystemSaveDataId system_save_data_id, u16 index, + SaveDataRank rank) { + return { + .program_id = program_id, + .user_id = user_id, + .system_save_data_id = system_save_data_id, + .type = type, + .rank = rank, + .index = index, + }; + } + + static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id, + SystemSaveDataId system_save_data_id, u16 index) { + return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary); + } + + static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id, + SystemSaveDataId system_save_data_id) { + return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary); + } + + std::string DebugInfo() const { + return fmt::format( + "[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, " + "rank={}, index={}]", + program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type), + static_cast<u8>(rank), index); + } +}; +static_assert(sizeof(SaveDataAttribute) == 0x40); +static_assert(std::is_trivially_destructible<SaveDataAttribute>::value); + +constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) { + return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) < + std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank); +} + +constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) { + return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank, + lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, + rhs.type, rhs.rank, rhs.index); +} + +constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) { + return !(lhs == rhs); +} + +struct SaveDataExtraData { + SaveDataAttribute attr; + u64 owner_id; + s64 timestamp; + u32 flags; + INSERT_PADDING_BYTES(4); + s64 available_size; + s64 journal_size; + s64 commit_id; + INSERT_PADDING_BYTES(0x190); +}; +static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size."); +static_assert(std::is_trivially_copyable_v<SaveDataExtraData>, + "Data type must be trivially copyable."); + +struct HashSalt { + static constexpr size_t Size = 32; + + std::array<u8, Size> value; +}; +static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable."); +static_assert(sizeof(HashSalt) == HashSalt::Size); + +} // namespace FileSys diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index cbf411a20..106922e04 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -14,48 +14,11 @@ namespace FileSys { namespace { -void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) { - if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) { - if (meta.zero_1 != 0) { - LOG_WARNING(Service_FS, - "Possibly incorrect SaveDataAttribute, type is " - "SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).", - meta.zero_1); - } - if (meta.zero_2 != 0) { - LOG_WARNING(Service_FS, - "Possibly incorrect SaveDataAttribute, type is " - "SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).", - meta.zero_2); - } - if (meta.zero_3 != 0) { - LOG_WARNING(Service_FS, - "Possibly incorrect SaveDataAttribute, type is " - "SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).", - meta.zero_3); - } - } - - if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) { - LOG_WARNING(Service_FS, - "Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is " - "non-zero ({:016X}).", - meta.title_id); - } - - if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) { - LOG_WARNING(Service_FS, - "Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is " - "non-zero ({:016X}{:016X})", - meta.user_id[1], meta.user_id[0]); - } -} - bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) { - return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage || - (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User - (attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) && - attr.title_id == 0 && attr.save_id == 0); + return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary || + (space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User + (attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) && + attr.program_id == 0 && attr.system_save_data_id == 0); } std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id, @@ -63,7 +26,7 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u // Only detect nand user saves. const auto space_id_path = [space_id]() -> std::string_view { switch (space_id) { - case SaveDataSpaceId::NandUser: + case SaveDataSpaceId::User: return "/user/save"; default: return ""; @@ -79,9 +42,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u // Only detect account/device saves from the future location. switch (type) { - case SaveDataType::SaveData: + case SaveDataType::Account: return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id); - case SaveDataType::DeviceSaveData: + case SaveDataType::Device: return fmt::format("{}/device/{:016X}/0", space_id_path, title_id); default: return ""; @@ -90,13 +53,6 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u } // Anonymous namespace -std::string SaveDataAttribute::DebugInfo() const { - return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, " - "rank={}, index={}]", - title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type), - static_cast<u8>(rank), index); -} - SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_, VirtualDir save_directory_) : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} { @@ -108,18 +64,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_, SaveDataFactory::~SaveDataFactory() = default; VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const { - PrintSaveDataAttributeWarnings(meta); - - const auto save_directory = - GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); + const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id, + meta.user_id, meta.system_save_data_id); return dir->CreateDirectoryRelative(save_directory); } VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { - const auto save_directory = - GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); + const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id, + meta.user_id, meta.system_save_data_id); auto out = dir->GetDirectoryRelative(save_directory); @@ -136,11 +90,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { switch (space) { - case SaveDataSpaceId::NandSystem: + case SaveDataSpaceId::System: return "/system/"; - case SaveDataSpaceId::NandUser: + case SaveDataSpaceId::User: return "/user/"; - case SaveDataSpaceId::TemporaryStorage: + case SaveDataSpaceId::Temporary: return "/temp/"; default: ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); @@ -153,7 +107,7 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir, u128 user_id, u64 save_id) { // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should // be interpreted as the title id of the current process. - if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { + if (type == SaveDataType::Account || type == SaveDataType::Device) { if (title_id == 0) { title_id = program_id; } @@ -173,16 +127,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir, std::string out = GetSaveDataSpaceIdPath(space); switch (type) { - case SaveDataType::SystemSaveData: + case SaveDataType::System: return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); - case SaveDataType::SaveData: - case SaveDataType::DeviceSaveData: + case SaveDataType::Account: + case SaveDataType::Device: return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], title_id); - case SaveDataType::TemporaryStorage: + case SaveDataType::Temporary: return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], title_id); - case SaveDataType::CacheStorage: + case SaveDataType::Cache: return fmt::format("{}save/cache/{:016X}", out, title_id); default: ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type)); @@ -202,7 +156,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future) SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const { const auto path = - GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); + GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0); const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); @@ -221,7 +175,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value) const { const auto path = - GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); + GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0); const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index 5ab7e4d32..15dd4ec7d 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h @@ -7,6 +7,7 @@ #include <string> #include "common/common_funcs.h" #include "common/common_types.h" +#include "core/file_sys/fs_save_data_types.h" #include "core/file_sys/vfs/vfs.h" #include "core/hle/result.h" @@ -16,73 +17,6 @@ class System; namespace FileSys { -enum class SaveDataSpaceId : u8 { - NandSystem = 0, - NandUser = 1, - SdCardSystem = 2, - TemporaryStorage = 3, - SdCardUser = 4, - ProperSystem = 100, - SafeMode = 101, -}; - -enum class SaveDataType : u8 { - SystemSaveData = 0, - SaveData = 1, - BcatDeliveryCacheStorage = 2, - DeviceSaveData = 3, - TemporaryStorage = 4, - CacheStorage = 5, - SystemBcat = 6, -}; - -enum class SaveDataRank : u8 { - Primary = 0, - Secondary = 1, -}; - -enum class SaveDataFlags : u32 { - None = (0 << 0), - KeepAfterResettingSystemSaveData = (1 << 0), - KeepAfterRefurbishment = (1 << 1), - KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2), - NeedsSecureDelete = (1 << 3), -}; - -struct SaveDataAttribute { - u64 title_id; - u128 user_id; - u64 save_id; - SaveDataType type; - SaveDataRank rank; - u16 index; - INSERT_PADDING_BYTES_NOINIT(4); - u64 zero_1; - u64 zero_2; - u64 zero_3; - - std::string DebugInfo() const; -}; -static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size."); - -struct SaveDataExtraData { - SaveDataAttribute attr; - u64 owner_id; - s64 timestamp; - SaveDataFlags flags; - INSERT_PADDING_BYTES_NOINIT(4); - s64 available_size; - s64 journal_size; - s64 commit_id; - std::array<u8, 0x190> unused; -}; -static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size."); - -struct SaveDataSize { - u64 normal; - u64 journal; -}; - constexpr const char* GetSaveDataSizeFileName() { return ".yuzu_save_size"; } |