mirror of https://git.suyu.dev/suyu/suyu
fs: Add and use fs_save_data_types.h
This commit is contained in:
parent
4c71bf3d90
commit
2b18957365
|
@ -58,6 +58,7 @@ add_library(core STATIC
|
||||||
file_sys/fs_operate_range.h
|
file_sys/fs_operate_range.h
|
||||||
file_sys/fs_path.h
|
file_sys/fs_path.h
|
||||||
file_sys/fs_path_utility.h
|
file_sys/fs_path_utility.h
|
||||||
|
file_sys/fs_save_data_types.h
|
||||||
file_sys/fs_string_util.h
|
file_sys/fs_string_util.h
|
||||||
file_sys/fsmitm_romfsbuild.cpp
|
file_sys/fsmitm_romfsbuild.cpp
|
||||||
file_sys/fsmitm_romfsbuild.h
|
file_sys/fsmitm_romfsbuild.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
|
|
@ -14,48 +14,11 @@ namespace FileSys {
|
||||||
|
|
||||||
namespace {
|
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) {
|
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
|
||||||
return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage ||
|
return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary ||
|
||||||
(space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
|
(space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User
|
||||||
(attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) &&
|
(attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) &&
|
||||||
attr.title_id == 0 && attr.save_id == 0);
|
attr.program_id == 0 && attr.system_save_data_id == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
|
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.
|
// Only detect nand user saves.
|
||||||
const auto space_id_path = [space_id]() -> std::string_view {
|
const auto space_id_path = [space_id]() -> std::string_view {
|
||||||
switch (space_id) {
|
switch (space_id) {
|
||||||
case SaveDataSpaceId::NandUser:
|
case SaveDataSpaceId::User:
|
||||||
return "/user/save";
|
return "/user/save";
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
|
@ -79,9 +42,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
|
||||||
|
|
||||||
// Only detect account/device saves from the future location.
|
// Only detect account/device saves from the future location.
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SaveDataType::SaveData:
|
case SaveDataType::Account:
|
||||||
return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
|
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);
|
return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
|
@ -90,13 +53,6 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // 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_,
|
SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
|
||||||
VirtualDir save_directory_)
|
VirtualDir save_directory_)
|
||||||
: system{system_}, program_id{program_id_}, dir{std::move(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;
|
SaveDataFactory::~SaveDataFactory() = default;
|
||||||
|
|
||||||
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||||
PrintSaveDataAttributeWarnings(meta);
|
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
|
||||||
|
meta.user_id, meta.system_save_data_id);
|
||||||
const auto save_directory =
|
|
||||||
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
|
||||||
|
|
||||||
return dir->CreateDirectoryRelative(save_directory);
|
return dir->CreateDirectoryRelative(save_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||||
|
|
||||||
const auto save_directory =
|
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
|
||||||
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
meta.user_id, meta.system_save_data_id);
|
||||||
|
|
||||||
auto out = dir->GetDirectoryRelative(save_directory);
|
auto out = dir->GetDirectoryRelative(save_directory);
|
||||||
|
|
||||||
|
@ -136,11 +90,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
|
||||||
|
|
||||||
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
|
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
|
||||||
switch (space) {
|
switch (space) {
|
||||||
case SaveDataSpaceId::NandSystem:
|
case SaveDataSpaceId::System:
|
||||||
return "/system/";
|
return "/system/";
|
||||||
case SaveDataSpaceId::NandUser:
|
case SaveDataSpaceId::User:
|
||||||
return "/user/";
|
return "/user/";
|
||||||
case SaveDataSpaceId::TemporaryStorage:
|
case SaveDataSpaceId::Temporary:
|
||||||
return "/temp/";
|
return "/temp/";
|
||||||
default:
|
default:
|
||||||
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
|
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) {
|
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
|
// 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.
|
// 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) {
|
if (title_id == 0) {
|
||||||
title_id = program_id;
|
title_id = program_id;
|
||||||
}
|
}
|
||||||
|
@ -173,16 +127,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
|
||||||
std::string out = GetSaveDataSpaceIdPath(space);
|
std::string out = GetSaveDataSpaceIdPath(space);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SaveDataType::SystemSaveData:
|
case SaveDataType::System:
|
||||||
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
|
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
|
||||||
case SaveDataType::SaveData:
|
case SaveDataType::Account:
|
||||||
case SaveDataType::DeviceSaveData:
|
case SaveDataType::Device:
|
||||||
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
||||||
title_id);
|
title_id);
|
||||||
case SaveDataType::TemporaryStorage:
|
case SaveDataType::Temporary:
|
||||||
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
||||||
title_id);
|
title_id);
|
||||||
case SaveDataType::CacheStorage:
|
case SaveDataType::Cache:
|
||||||
return fmt::format("{}save/cache/{:016X}", out, title_id);
|
return fmt::format("{}save/cache/{:016X}", out, title_id);
|
||||||
default:
|
default:
|
||||||
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
|
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,
|
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||||
u128 user_id) const {
|
u128 user_id) const {
|
||||||
const auto path =
|
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 relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||||
|
|
||||||
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
|
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,
|
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||||
SaveDataSize new_value) const {
|
SaveDataSize new_value) const {
|
||||||
const auto path =
|
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 relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||||
|
|
||||||
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/file_sys/fs_save_data_types.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
@ -16,73 +17,6 @@ class System;
|
||||||
|
|
||||||
namespace FileSys {
|
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() {
|
constexpr const char* GetSaveDataSizeFileName() {
|
||||||
return ".yuzu_save_size";
|
return ".yuzu_save_size";
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,13 +123,13 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
|
||||||
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
|
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
|
||||||
|
|
||||||
FileSys::SaveDataAttribute attribute{};
|
FileSys::SaveDataAttribute attribute{};
|
||||||
attribute.title_id = m_applet->program_id;
|
attribute.program_id = m_applet->program_id;
|
||||||
attribute.user_id = user_id.AsU128();
|
attribute.user_id = user_id.AsU128();
|
||||||
attribute.type = FileSys::SaveDataType::SaveData;
|
attribute.type = FileSys::SaveDataType::Account;
|
||||||
|
|
||||||
FileSys::VirtualDir save_data{};
|
FileSys::VirtualDir save_data{};
|
||||||
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
|
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
|
||||||
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
|
&save_data, FileSys::SaveDataSpaceId::User, attribute));
|
||||||
|
|
||||||
*out_size = 0;
|
*out_size = 0;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|
|
@ -72,7 +72,7 @@ void ISaveDataInfoReader::FindAllSaves(FileSys::SaveDataSpaceId space) {
|
||||||
for (const auto& type : save_root->GetSubdirectories()) {
|
for (const auto& type : save_root->GetSubdirectories()) {
|
||||||
if (type->GetName() == "save") {
|
if (type->GetName() == "save") {
|
||||||
FindNormalSaves(space, type);
|
FindNormalSaves(space, type);
|
||||||
} else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
|
} else if (space == FileSys::SaveDataSpaceId::Temporary) {
|
||||||
FindTemporaryStorageSaves(space, type);
|
FindTemporaryStorageSaves(space, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ void ISaveDataInfoReader::FindNormalSaves(FileSys::SaveDataSpaceId space,
|
||||||
info.emplace_back(SaveDataInfo{
|
info.emplace_back(SaveDataInfo{
|
||||||
0,
|
0,
|
||||||
space,
|
space,
|
||||||
FileSys::SaveDataType::SystemSaveData,
|
FileSys::SaveDataType::System,
|
||||||
{},
|
{},
|
||||||
user_id_numeric,
|
user_id_numeric,
|
||||||
save_id_numeric,
|
save_id_numeric,
|
||||||
|
@ -115,8 +115,7 @@ void ISaveDataInfoReader::FindNormalSaves(FileSys::SaveDataSpaceId space,
|
||||||
info.emplace_back(SaveDataInfo{
|
info.emplace_back(SaveDataInfo{
|
||||||
0,
|
0,
|
||||||
space,
|
space,
|
||||||
device ? FileSys::SaveDataType::DeviceSaveData
|
device ? FileSys::SaveDataType::Device : FileSys::SaveDataType::Account,
|
||||||
: FileSys::SaveDataType::SaveData,
|
|
||||||
{},
|
{},
|
||||||
user_id_numeric,
|
user_id_numeric,
|
||||||
save_id_numeric,
|
save_id_numeric,
|
||||||
|
@ -145,7 +144,7 @@ void ISaveDataInfoReader::FindTemporaryStorageSaves(FileSys::SaveDataSpaceId spa
|
||||||
info.emplace_back(SaveDataInfo{
|
info.emplace_back(SaveDataInfo{
|
||||||
0,
|
0,
|
||||||
space,
|
space,
|
||||||
FileSys::SaveDataType::TemporaryStorage,
|
FileSys::SaveDataType::Temporary,
|
||||||
{},
|
{},
|
||||||
user_id_numeric,
|
user_id_numeric,
|
||||||
stoull_be(type->GetName()),
|
stoull_be(type->GetName()),
|
||||||
|
|
|
@ -224,23 +224,23 @@ Result FSP_SRV::OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface) {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FSP_SRV::CreateSaveDataFileSystem(std::array<u8, 0x40> save_create_struct,
|
Result FSP_SRV::CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
|
||||||
FileSys::SaveDataAttribute save_struct, u128 uid) {
|
FileSys::SaveDataAttribute save_struct, u128 uid) {
|
||||||
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
|
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
|
||||||
uid[1], uid[0]);
|
uid[1], uid[0]);
|
||||||
|
|
||||||
FileSys::VirtualDir save_data_dir{};
|
FileSys::VirtualDir save_data_dir{};
|
||||||
R_RETURN(save_data_controller->CreateSaveData(&save_data_dir,
|
R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::User,
|
||||||
FileSys::SaveDataSpaceId::NandUser, save_struct));
|
save_struct));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(std::array<u8, 0x40> save_create_struct,
|
Result FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(
|
||||||
FileSys::SaveDataAttribute save_struct) {
|
FileSys::SaveDataCreationInfo save_create_struct, FileSys::SaveDataAttribute save_struct) {
|
||||||
LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
|
LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
|
||||||
|
|
||||||
FileSys::VirtualDir save_data_dir{};
|
FileSys::VirtualDir save_data_dir{};
|
||||||
R_RETURN(save_data_controller->CreateSaveData(
|
R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::System,
|
||||||
&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, save_struct));
|
save_struct));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
|
Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
|
||||||
|
@ -253,17 +253,17 @@ Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
|
||||||
|
|
||||||
FileSys::StorageId id{};
|
FileSys::StorageId id{};
|
||||||
switch (space_id) {
|
switch (space_id) {
|
||||||
case FileSys::SaveDataSpaceId::NandUser:
|
case FileSys::SaveDataSpaceId::User:
|
||||||
id = FileSys::StorageId::NandUser;
|
id = FileSys::StorageId::NandUser;
|
||||||
break;
|
break;
|
||||||
case FileSys::SaveDataSpaceId::SdCardSystem:
|
case FileSys::SaveDataSpaceId::SdSystem:
|
||||||
case FileSys::SaveDataSpaceId::SdCardUser:
|
case FileSys::SaveDataSpaceId::SdUser:
|
||||||
id = FileSys::StorageId::SdCard;
|
id = FileSys::StorageId::SdCard;
|
||||||
break;
|
break;
|
||||||
case FileSys::SaveDataSpaceId::NandSystem:
|
case FileSys::SaveDataSpaceId::System:
|
||||||
id = FileSys::StorageId::NandSystem;
|
id = FileSys::StorageId::NandSystem;
|
||||||
break;
|
break;
|
||||||
case FileSys::SaveDataSpaceId::TemporaryStorage:
|
case FileSys::SaveDataSpaceId::Temporary:
|
||||||
case FileSys::SaveDataSpaceId::ProperSystem:
|
case FileSys::SaveDataSpaceId::ProperSystem:
|
||||||
case FileSys::SaveDataSpaceId::SafeMode:
|
case FileSys::SaveDataSpaceId::SafeMode:
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
|
@ -302,8 +302,8 @@ Result FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(
|
||||||
OutInterface<ISaveDataInfoReader> out_interface) {
|
OutInterface<ISaveDataInfoReader> out_interface) {
|
||||||
LOG_WARNING(Service_FS, "(STUBBED) called");
|
LOG_WARNING(Service_FS, "(STUBBED) called");
|
||||||
|
|
||||||
*out_interface = std::make_shared<ISaveDataInfoReader>(
|
*out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller,
|
||||||
system, save_data_controller, FileSys::SaveDataSpaceId::TemporaryStorage);
|
FileSys::SaveDataSpaceId::Temporary);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
@ -323,11 +323,11 @@ Result FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
|
||||||
[[maybe_unused]] constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
|
[[maybe_unused]] constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
|
||||||
|
|
||||||
LOG_WARNING(Service_FS,
|
LOG_WARNING(Service_FS,
|
||||||
"(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
|
"(STUBBED) called, flags={}, space_id={}, attribute.program_id={:016X}\n"
|
||||||
"attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
|
"attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
|
||||||
"attribute.type={}, attribute.rank={}, attribute.index={}",
|
"attribute.type={}, attribute.rank={}, attribute.index={}",
|
||||||
flags, space_id, attribute.title_id, attribute.user_id[1], attribute.user_id[0],
|
flags, space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
|
||||||
attribute.save_id, attribute.type, attribute.rank, attribute.index);
|
attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "core/file_sys/fs_save_data_types.h"
|
||||||
#include "core/hle/service/cmif_types.h"
|
#include "core/hle/service/cmif_types.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
@ -60,10 +61,10 @@ private:
|
||||||
Result OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
|
Result OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
|
||||||
FileSystemProxyType type, u64 open_program_id);
|
FileSystemProxyType type, u64 open_program_id);
|
||||||
Result OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface);
|
Result OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface);
|
||||||
Result CreateSaveDataFileSystem(std::array<u8, 0x40> save_create_struct,
|
Result CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
|
||||||
FileSys::SaveDataAttribute save_struct, u128 uid);
|
FileSys::SaveDataAttribute save_struct, u128 uid);
|
||||||
Result CreateSaveDataFileSystemBySystemSaveDataId(std::array<u8, 0x40> save_create_struct,
|
Result CreateSaveDataFileSystemBySystemSaveDataId(
|
||||||
FileSys::SaveDataAttribute save_struct);
|
FileSys::SaveDataCreationInfo save_create_struct, FileSys::SaveDataAttribute save_struct);
|
||||||
Result OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
|
Result OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
|
||||||
FileSys::SaveDataSpaceId space_id,
|
FileSys::SaveDataSpaceId space_id,
|
||||||
FileSys::SaveDataAttribute attribute);
|
FileSys::SaveDataAttribute attribute);
|
||||||
|
|
|
@ -2323,15 +2323,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
|
||||||
ASSERT(user_id);
|
ASSERT(user_id);
|
||||||
|
|
||||||
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
||||||
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser,
|
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
|
||||||
FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0);
|
program_id, user_id->AsU128(), 0);
|
||||||
|
|
||||||
path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
|
path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
|
||||||
} else {
|
} else {
|
||||||
// Device save data
|
// Device save data
|
||||||
const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
||||||
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser,
|
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
|
||||||
FileSys::SaveDataType::SaveData, program_id, {}, 0);
|
program_id, {}, 0);
|
||||||
|
|
||||||
path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path);
|
path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path);
|
||||||
}
|
}
|
||||||
|
@ -2672,7 +2672,7 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) {
|
||||||
vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
|
vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
|
||||||
|
|
||||||
const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath(
|
const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath(
|
||||||
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage,
|
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache,
|
||||||
0 /* program_id */, {}, 0);
|
0 /* program_id */, {}, 0);
|
||||||
|
|
||||||
const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path);
|
const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path);
|
||||||
|
|
Loading…
Reference in New Issue