Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Savefixes vii #2279

Merged
merged 3 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/common/elf_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class ElfInfo {
static constexpr u32 FW_40 = 0x4000000;
static constexpr u32 FW_45 = 0x4500000;
static constexpr u32 FW_50 = 0x5000000;
static constexpr u32 FW_55 = 0x5500000;
static constexpr u32 FW_80 = 0x8000000;

static ElfInfo& Instance() {
Expand Down
21 changes: 16 additions & 5 deletions src/core/libraries/save_data/save_backup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,17 @@ static void BackupThreadBody() {
std::scoped_lock lk{g_backup_queue_mutex};
g_backup_queue.front().done = true;
}
std::this_thread::sleep_for(std::chrono::seconds(5)); // Don't backup too often
{
std::scoped_lock lk{g_backup_queue_mutex};
g_backup_queue.pop_front();
g_result_queue.push_back(std::move(req));
if (g_result_queue.size() > 20) {
g_result_queue.pop_front();
if (req.origin != OrbisSaveDataEventType::__DO_NOT_SAVE) {
g_result_queue.push_back(std::move(req));
if (g_result_queue.size() > 20) {
g_result_queue.pop_front();
}
}
}
std::this_thread::sleep_for(std::chrono::seconds(5)); // Don't backup too often
}
g_backup_status = WorkerStatus::NotStarted;
}
Expand All @@ -141,19 +143,28 @@ void StartThread() {
LOG_DEBUG(Lib_SaveData, "Starting backup thread");
g_backup_status = WorkerStatus::Waiting;
g_backup_thread = std::jthread{BackupThreadBody};
static std::once_flag flag;
std::call_once(flag, [] {
std::at_quick_exit([] {
StopThread();
while (GetWorkerStatus() != WorkerStatus::NotStarted) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
});
}

void StopThread() {
if (g_backup_status == WorkerStatus::NotStarted || g_backup_status == WorkerStatus::Stopping) {
return;
}
LOG_DEBUG(Lib_SaveData, "Stopping backup thread");
g_backup_status = WorkerStatus::Stopping;
{
std::scoped_lock lk{g_backup_queue_mutex};
g_backup_queue.emplace_back(BackupRequest{});
}
g_backup_thread_semaphore.release();
g_backup_status = WorkerStatus::Stopping;
}

bool NewRequest(OrbisUserServiceUserId user_id, std::string_view title_id,
Expand Down
2 changes: 2 additions & 0 deletions src/core/libraries/save_data/save_backup.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ enum class OrbisSaveDataEventType : u32 {
UMOUNT_BACKUP = 1,
BACKUP = 2,
SAVE_DATA_MEMORY_SYNC = 3,

__DO_NOT_SAVE = 1000000, // This value is only for the backup thread
};

struct BackupRequest {
Expand Down
53 changes: 27 additions & 26 deletions src/core/libraries/save_data/save_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "common/path_util.h"
#include "common/singleton.h"
#include "core/file_sys/fs.h"
#include "save_backup.h"
#include "save_instance.h"

constexpr auto OrbisSaveDataBlocksMin2 = 96; // 3MiB
Expand Down Expand Up @@ -45,14 +46,13 @@ static const std::unordered_map<std::string, std::string> default_title = {

namespace Libraries::SaveData {

std::filesystem::path SaveInstance::MakeTitleSavePath(OrbisUserServiceUserId user_id,
std::string_view game_serial) {
fs::path SaveInstance::MakeTitleSavePath(OrbisUserServiceUserId user_id,
std::string_view game_serial) {
return Config::GetSaveDataPath() / std::to_string(user_id) / game_serial;
}

std::filesystem::path SaveInstance::MakeDirSavePath(OrbisUserServiceUserId user_id,
std::string_view game_serial,
std::string_view dir_name) {
fs::path SaveInstance::MakeDirSavePath(OrbisUserServiceUserId user_id, std::string_view game_serial,
std::string_view dir_name) {
return Config::GetSaveDataPath() / std::to_string(user_id) / game_serial / dir_name;
}

Expand All @@ -65,7 +65,7 @@ uint64_t SaveInstance::GetMaxBlockFromSFO(const PSF& psf) {
return *(uint64_t*)value.data();
}

std::filesystem::path SaveInstance::GetParamSFOPath(const std::filesystem::path& dir_path) {
fs::path SaveInstance::GetParamSFOPath(const fs::path& dir_path) {
return dir_path / sce_sys / "param.sfo";
}

Expand Down Expand Up @@ -129,7 +129,6 @@ SaveInstance& SaveInstance::operator=(SaveInstance&& other) noexcept {
save_path = std::move(other.save_path);
param_sfo_path = std::move(other.param_sfo_path);
corrupt_file_path = std::move(other.corrupt_file_path);
corrupt_file = std::move(other.corrupt_file);
param_sfo = std::move(other.param_sfo);
mount_point = std::move(other.mount_point);
max_blocks = other.max_blocks;
Expand All @@ -142,7 +141,8 @@ SaveInstance& SaveInstance::operator=(SaveInstance&& other) noexcept {
return *this;
}

void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_corrupt) {
void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_corrupt,
bool dont_restore_backup) {
if (mounted) {
UNREACHABLE_MSG("Save instance is already mounted");
}
Expand All @@ -161,25 +161,27 @@ void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_cor
}
exists = true;
} else {
std::optional<fs::filesystem_error> err;
if (!ignore_corrupt && fs::exists(corrupt_file_path)) {
throw std::filesystem::filesystem_error(
"Corrupted save data", corrupt_file_path,
std::make_error_code(std::errc::illegal_byte_sequence));
err = fs::filesystem_error("Corrupted save data", corrupt_file_path,
std::make_error_code(std::errc::illegal_byte_sequence));
} else if (!param_sfo.Open(param_sfo_path)) {
err = fs::filesystem_error("Failed to read param.sfo", param_sfo_path,
std::make_error_code(std::errc::illegal_byte_sequence));
}
if (!param_sfo.Open(param_sfo_path)) {
throw std::filesystem::filesystem_error(
"Failed to read param.sfo", param_sfo_path,
std::make_error_code(std::errc::illegal_byte_sequence));
if (err.has_value()) {
if (dont_restore_backup) {
throw err.value();
}
if (Backup::Restore(save_path)) {
return SetupAndMount(read_only, copy_icon, ignore_corrupt, true);
}
}
}

if (!ignore_corrupt && !read_only) {
int err = corrupt_file.Open(corrupt_file_path, Common::FS::FileAccessMode::Write);
if (err != 0) {
throw std::filesystem::filesystem_error(
"Failed to open corrupted file", corrupt_file_path,
std::make_error_code(std::errc::illegal_byte_sequence));
}
Common::FS::IOFile f(corrupt_file_path, Common::FS::FileAccessMode::Write);
f.Close();
}

max_blocks = static_cast<int>(GetMaxBlockFromSFO(param_sfo));
Expand All @@ -197,12 +199,11 @@ void SaveInstance::Umount() {
mounted = false;
const bool ok = param_sfo.Encode(param_sfo_path);
if (!ok) {
throw std::filesystem::filesystem_error("Failed to write param.sfo", param_sfo_path,
std::make_error_code(std::errc::permission_denied));
throw fs::filesystem_error("Failed to write param.sfo", param_sfo_path,
std::make_error_code(std::errc::permission_denied));
}
param_sfo = PSF();

corrupt_file.Close();
fs::remove(corrupt_file_path);
g_mnt->Unmount(save_path, mount_point);
}
Expand All @@ -216,8 +217,8 @@ void SaveInstance::CreateFiles() {

const bool ok = param_sfo.Encode(param_sfo_path);
if (!ok) {
throw std::filesystem::filesystem_error("Failed to write param.sfo", param_sfo_path,
std::make_error_code(std::errc::permission_denied));
throw fs::filesystem_error("Failed to write param.sfo", param_sfo_path,
std::make_error_code(std::errc::permission_denied));
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/core/libraries/save_data/save_instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ class SaveInstance {
std::filesystem::path param_sfo_path;
std::filesystem::path corrupt_file_path;

Common::FS::IOFile corrupt_file;

PSF param_sfo;
std::string mount_point;

Expand Down Expand Up @@ -80,7 +78,8 @@ class SaveInstance {
SaveInstance& operator=(const SaveInstance& other) = delete;
SaveInstance& operator=(SaveInstance&& other) noexcept;

void SetupAndMount(bool read_only = false, bool copy_icon = false, bool ignore_corrupt = false);
void SetupAndMount(bool read_only = false, bool copy_icon = false, bool ignore_corrupt = false,
bool dont_restore_backup = false);

void Umount();

Expand Down
Loading