SaveData compatibility with old firmwares

This commit is contained in:
Vinicius Rangel 2024-09-22 20:50:10 -03:00
parent 646b2f4679
commit 00c2a5a1eb
No known key found for this signature in database
GPG Key ID: A5B154D904B761D9
5 changed files with 171 additions and 75 deletions

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/elf_info.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/system/commondialog.h" #include "core/libraries/system/commondialog.h"

View File

@ -15,6 +15,7 @@
using namespace ImGui; using namespace ImGui;
using namespace Libraries::CommonDialog; using namespace Libraries::CommonDialog;
using Common::ElfInfo;
constexpr u32 OrbisSaveDataBlockSize = 32768; // 32 KiB constexpr u32 OrbisSaveDataBlockSize = 32768; // 32 KiB
@ -48,7 +49,7 @@ void SaveDialogResult::CopyTo(OrbisSaveDataDialogResult& result) const {
result.mode = this->mode; result.mode = this->mode;
result.result = this->result; result.result = this->result;
result.buttonId = this->button_id; result.buttonId = this->button_id;
if (has_item) { if (mode == SaveDataDialogMode::LIST || ElfInfo::Instance().FirmwareVer() >= ElfInfo::FW_45) {
if (result.dirName != nullptr) { if (result.dirName != nullptr) {
result.dirName->data.FromString(this->dir_name); result.dirName->data.FromString(this->dir_name);
} }
@ -202,6 +203,7 @@ SaveDialogState::SystemState::SystemState(const SaveDialogState& state,
auto& sys = *param.sysMsgParam; auto& sys = *param.sysMsgParam;
switch (sys.msgType) { switch (sys.msgType) {
case SystemMessageType::NODATA: { case SystemMessageType::NODATA: {
return_cancel = true;
this->msg = "There is no saved data"; this->msg = "There is no saved data";
} break; } break;
case SystemMessageType::CONFIRM: case SystemMessageType::CONFIRM:
@ -214,6 +216,7 @@ SaveDialogState::SystemState::SystemState(const SaveDialogState& state,
M("Do you want to overwrite the existing saved data?", "##UNKNOWN##", "##UNKNOWN##"); M("Do you want to overwrite the existing saved data?", "##UNKNOWN##", "##UNKNOWN##");
break; break;
case SystemMessageType::NOSPACE: case SystemMessageType::NOSPACE:
return_cancel = true;
M(fmt::format( M(fmt::format(
"There is not enough space to save the data. To continue {} free space is required.", "There is not enough space to save the data. To continue {} free space is required.",
SpaceSizeToString(sys.value * OrbisSaveDataBlockSize)), SpaceSizeToString(sys.value * OrbisSaveDataBlockSize)),
@ -225,12 +228,15 @@ SaveDialogState::SystemState::SystemState(const SaveDialogState& state,
M("Saving...", "Loading...", "Deleting..."); M("Saving...", "Loading...", "Deleting...");
break; break;
case SystemMessageType::FILE_CORRUPTED: case SystemMessageType::FILE_CORRUPTED:
return_cancel = true;
this->msg = "The saved data is corrupted."; this->msg = "The saved data is corrupted.";
break; break;
case SystemMessageType::FINISHED: case SystemMessageType::FINISHED:
return_cancel = true;
M("Saved successfully.", "Loading complete.", "Deletion complete."); M("Saved successfully.", "Loading complete.", "Deletion complete.");
break; break;
case SystemMessageType::NOSPACE_CONTINUABLE: case SystemMessageType::NOSPACE_CONTINUABLE:
return_cancel = true;
M(fmt::format("There is not enough space to save the data. {} free space is required.", M(fmt::format("There is not enough space to save the data. {} free space is required.",
SpaceSizeToString(sys.value * OrbisSaveDataBlockSize)), SpaceSizeToString(sys.value * OrbisSaveDataBlockSize)),
"##UNKNOWN##", "##UNKNOWN##"); "##UNKNOWN##", "##UNKNOWN##");
@ -282,29 +288,36 @@ SaveDialogState::ErrorCodeState::ErrorCodeState(const OrbisSaveDataDialogParam&
} }
SaveDialogState::ProgressBarState::ProgressBarState(const SaveDialogState& state, SaveDialogState::ProgressBarState::ProgressBarState(const SaveDialogState& state,
const OrbisSaveDataDialogParam& param) { const OrbisSaveDataDialogParam& param) {
static auto fw_ver = ElfInfo::Instance().FirmwareVer();
this->progress = 0; this->progress = 0;
auto& bar = *param.progressBarParam; auto& bar = *param.progressBarParam;
switch (bar.sysMsgType) {
case ProgressSystemMessageType::INVALID: if (bar.msg != nullptr) {
this->msg = bar.msg != nullptr ? std::string{bar.msg} : std::string{}; this->msg = std::string{bar.msg};
break; } else {
case ProgressSystemMessageType::PROGRESS: switch (bar.sysMsgType) {
switch (state.type) { case ProgressSystemMessageType::INVALID:
case DialogType::SAVE: this->msg = "INVALID";
this->msg = "Saving...";
break; break;
case DialogType::LOAD: case ProgressSystemMessageType::PROGRESS:
this->msg = "Loading..."; switch (state.type) {
case DialogType::SAVE:
this->msg = "Saving...";
break;
case DialogType::LOAD:
this->msg = "Loading...";
break;
case DialogType::DELETE:
this->msg = "Deleting...";
break;
}
break; break;
case DialogType::DELETE: case ProgressSystemMessageType::RESTORE:
this->msg = "Deleting..."; this->msg = "Restoring saved data...";
break; break;
} }
break;
case ProgressSystemMessageType::RESTORE:
this->msg = "Restoring saved data...";
break;
} }
} }
@ -352,11 +365,8 @@ void SaveDialogUi::Finish(ButtonId buttonId, Result r) {
result->result = r; result->result = r;
result->button_id = buttonId; result->button_id = buttonId;
result->user_data = this->state->user_data; result->user_data = this->state->user_data;
if (state) { if (state && state->mode != SaveDataDialogMode::LIST && !state->save_list.empty()) {
if (state->mode != SaveDataDialogMode::LIST && !state->save_list.empty()) { result->dir_name = state->save_list.front().dir_name;
result->dir_name = state->save_list.front().dir_name;
}
result->has_item = state->mode == SaveDataDialogMode::LIST || !state->save_list.empty();
} }
} }
if (status) { if (status) {
@ -642,6 +652,8 @@ void SaveDialogUi::DrawUser() {
if (!state->save_list.empty()) { if (!state->save_list.empty()) {
DrawItem(0, state->save_list.front(), false); DrawItem(0, state->save_list.front(), false);
} else if (state->new_item) {
DrawItem(0, *state->new_item, false);
} }
auto has_btn = btn_type != ButtonType::NONE; auto has_btn = btn_type != ButtonType::NONE;
@ -666,7 +678,7 @@ void SaveDialogUi::DrawUser() {
if (has_btn) { if (has_btn) {
int count = 1; int count = 1;
if (btn_type == ButtonType::YESNO || btn_type == ButtonType::ONCANCEL) { if (btn_type == ButtonType::YESNO || btn_type == ButtonType::OKCANCEL) {
++count; ++count;
} }
@ -682,19 +694,28 @@ void SaveDialogUi::DrawUser() {
} }
SameLine(); SameLine();
if (Button("No", BUTTON_SIZE)) { if (Button("No", BUTTON_SIZE)) {
Finish(ButtonId::NO); if (ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::NO);
}
} }
if (first_render || IsKeyPressed(ImGuiKey_GamepadFaceRight)) { if (first_render || IsKeyPressed(ImGuiKey_GamepadFaceRight)) {
SetItemCurrentNavFocus(); SetItemCurrentNavFocus();
} }
} else { } else {
if (Button("OK", BUTTON_SIZE)) { if (Button("OK", BUTTON_SIZE)) {
Finish(ButtonId::OK); if (btn_type == ButtonType::OK &&
ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::OK);
}
} }
if (first_render) { if (first_render) {
SetItemCurrentNavFocus(); SetItemCurrentNavFocus();
} }
if (btn_type == ButtonType::ONCANCEL) { if (btn_type == ButtonType::OKCANCEL) {
SameLine(); SameLine();
if (Button("Cancel", BUTTON_SIZE)) { if (Button("Cancel", BUTTON_SIZE)) {
Finish(ButtonId::INVALID, Result::USER_CANCELED); Finish(ButtonId::INVALID, Result::USER_CANCELED);
@ -713,6 +734,8 @@ void SaveDialogUi::DrawSystemMessage() {
if (!state->save_list.empty()) { if (!state->save_list.empty()) {
DrawItem(0, state->save_list.front(), false); DrawItem(0, state->save_list.front(), false);
} else if (state->new_item) {
DrawItem(0, *state->new_item, false);
} }
const auto ws = GetWindowSize(); const auto ws = GetWindowSize();
@ -736,12 +759,20 @@ void SaveDialogUi::DrawSystemMessage() {
}); });
BeginGroup(); BeginGroup();
if (Button(sys_state.show_no ? "Yes" : "OK", BUTTON_SIZE)) { if (Button(sys_state.show_no ? "Yes" : "OK", BUTTON_SIZE)) {
Finish(ButtonId::YES); if (sys_state.return_cancel && ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::YES);
}
} }
SameLine(); SameLine();
if (sys_state.show_no) { if (sys_state.show_no) {
if (Button("No", BUTTON_SIZE)) { if (Button("No", BUTTON_SIZE)) {
Finish(ButtonId::NO); if (ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::NO);
}
} }
} else if (sys_state.show_cancel) { } else if (sys_state.show_cancel) {
if (Button("Cancel", BUTTON_SIZE)) { if (Button("Cancel", BUTTON_SIZE)) {
@ -759,6 +790,8 @@ void SaveDialogUi::DrawErrorCode() {
if (!state->save_list.empty()) { if (!state->save_list.empty()) {
DrawItem(0, state->save_list.front(), false); DrawItem(0, state->save_list.front(), false);
} else if (state->new_item) {
DrawItem(0, *state->new_item, false);
} }
const auto ws = GetWindowSize(); const auto ws = GetWindowSize();
@ -774,7 +807,11 @@ void SaveDialogUi::DrawErrorCode() {
ws.y - FOOTER_HEIGHT + 5.0f, ws.y - FOOTER_HEIGHT + 5.0f,
}); });
if (Button("OK", BUTTON_SIZE)) { if (Button("OK", BUTTON_SIZE)) {
Finish(ButtonId::OK); if (ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::OK);
}
} }
if (first_render) { if (first_render) {
SetItemCurrentNavFocus(); SetItemCurrentNavFocus();
@ -788,6 +825,8 @@ void SaveDialogUi::DrawProgressBar() {
if (!state->save_list.empty()) { if (!state->save_list.empty()) {
DrawItem(0, state->save_list.front(), false); DrawItem(0, state->save_list.front(), false);
} else if (state->new_item) {
DrawItem(0, *state->new_item, false);
} }
const auto& msg = bar_state.msg; const auto& msg = bar_state.msg;

View File

@ -48,7 +48,7 @@ enum class ButtonType : u32 {
OK = 0, OK = 0,
YESNO = 1, YESNO = 1,
NONE = 2, NONE = 2,
ONCANCEL = 3, OKCANCEL = 3,
}; };
enum class UserMessageType : u32 { enum class UserMessageType : u32 {
@ -201,7 +201,6 @@ struct SaveDialogResult {
std::string dir_name{}; std::string dir_name{};
PSF param{}; PSF param{};
void* user_data{}; void* user_data{};
bool has_item{false};
void CopyTo(OrbisSaveDataDialogResult& result) const; void CopyTo(OrbisSaveDataDialogResult& result) const;
}; };
@ -223,6 +222,8 @@ public:
bool show_no{}; // Yes instead of OK bool show_no{}; // Yes instead of OK
bool show_cancel{}; bool show_cancel{};
bool return_cancel{};
SystemState(const SaveDialogState& state, const OrbisSaveDataDialogParam& param); SystemState(const SaveDialogState& state, const OrbisSaveDataDialogParam& param);
}; };
struct ErrorCodeState { struct ErrorCodeState {

View File

@ -28,11 +28,13 @@ namespace fs = std::filesystem;
namespace chrono = std::chrono; namespace chrono = std::chrono;
using Common::CString; using Common::CString;
using Common::ElfInfo;
namespace Libraries::SaveData { namespace Libraries::SaveData {
enum class Error : u32 { enum class Error : u32 {
OK = 0, OK = 0,
USER_SERVICE_NOT_INITIALIZED = 0x80960002,
PARAMETER = 0x809F0000, PARAMETER = 0x809F0000,
NOT_INITIALIZED = 0x809F0001, NOT_INITIALIZED = 0x809F0001,
OUT_OF_MEMORY = 0x809F0002, OUT_OF_MEMORY = 0x809F0002,
@ -191,7 +193,9 @@ struct OrbisSaveDataMemorySetup2 {
OrbisUserServiceUserId userId; OrbisUserServiceUserId userId;
size_t memorySize; size_t memorySize;
size_t iconMemorySize; size_t iconMemorySize;
// +4.5
const OrbisSaveDataParam* initParam; const OrbisSaveDataParam* initParam;
// +4.5
const OrbisSaveDataIcon* initIcon; const OrbisSaveDataIcon* initIcon;
std::array<u8, 24> _reserved; std::array<u8, 24> _reserved;
}; };
@ -241,6 +245,7 @@ struct OrbisSaveDataMountResult {
OrbisSaveDataMountPoint mount_point; OrbisSaveDataMountPoint mount_point;
OrbisSaveDataBlocks required_blocks; OrbisSaveDataBlocks required_blocks;
u32 _unused; u32 _unused;
// +4.5
OrbisSaveDataMountStatus mount_status; OrbisSaveDataMountStatus mount_status;
std::array<u8, 28> _reserved; std::array<u8, 28> _reserved;
s32 : 32; s32 : 32;
@ -278,8 +283,11 @@ struct OrbisSaveDataDirNameSearchResult {
int : 32; int : 32;
OrbisSaveDataDirName* dirNames; OrbisSaveDataDirName* dirNames;
u32 dirNamesNum; u32 dirNamesNum;
// +1.7
u32 setNum; u32 setNum;
// +1.7
OrbisSaveDataParam* params; OrbisSaveDataParam* params;
// +2.5
OrbisSaveDataSearchInfo* infos; OrbisSaveDataSearchInfo* infos;
std::array<u8, 12> _reserved; std::array<u8, 12> _reserved;
int : 32; int : 32;
@ -303,11 +311,13 @@ struct OrbisSaveDataEvent {
static bool g_initialized = false; static bool g_initialized = false;
static std::string g_game_serial; static std::string g_game_serial;
static u32 g_fw_ver;
static std::array<std::optional<SaveInstance>, 16> g_mount_slots; static std::array<std::optional<SaveInstance>, 16> g_mount_slots;
static void initialize() { static void initialize() {
g_initialized = true; g_initialized = true;
g_game_serial = Common::ElfInfo::Instance().GameSerial(); g_game_serial = ElfInfo::Instance().GameSerial();
g_fw_ver = ElfInfo::Instance().FirmwareVer();
} }
// game_00other | game*other // game_00other | game*other
@ -336,6 +346,16 @@ static bool match(std::string_view str, std::string_view pattern) {
return str_it == str.end() && pat_it == pattern.end(); return str_it == str.end() && pat_it == pattern.end();
} }
static Error setNotInitializedError() {
if (g_fw_ver < ElfInfo::FW_20) {
return Error::INTERNAL;
}
if (g_fw_ver < ElfInfo::FW_25) {
return Error::USER_SERVICE_NOT_INITIALIZED;
}
return Error::NOT_INITIALIZED;
}
static Error saveDataMount(const OrbisSaveDataMount2* mount_info, static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
OrbisSaveDataMountResult* mount_result) { OrbisSaveDataMountResult* mount_result) {
@ -351,7 +371,7 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
{ {
const auto save_path = SaveInstance::MakeDirSavePath(mount_info->userId, g_game_serial, const auto save_path = SaveInstance::MakeDirSavePath(mount_info->userId, g_game_serial,
mount_info->dirName->data); mount_info->dirName->data);
if (Backup::IsBackupExecutingFor(save_path)) { if (Backup::IsBackupExecutingFor(save_path) && g_fw_ver) {
return Error::BACKUP_BUSY; return Error::BACKUP_BUSY;
} }
} }
@ -360,11 +380,14 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
const bool is_ro = True(mount_mode & OrbisSaveDataMountMode::RDONLY); const bool is_ro = True(mount_mode & OrbisSaveDataMountMode::RDONLY);
const bool create = True(mount_mode & OrbisSaveDataMountMode::CREATE); const bool create = True(mount_mode & OrbisSaveDataMountMode::CREATE);
const bool create_if_not_exist = True(mount_mode & OrbisSaveDataMountMode::CREATE2); const bool create_if_not_exist =
True(mount_mode & OrbisSaveDataMountMode::CREATE2) && g_fw_ver >= ElfInfo::FW_45;
ASSERT(!create || !create_if_not_exist); // Can't have both ASSERT(!create || !create_if_not_exist); // Can't have both
const bool copy_icon = True(mount_mode & OrbisSaveDataMountMode::COPY_ICON); const bool copy_icon = True(mount_mode & OrbisSaveDataMountMode::COPY_ICON);
const bool ignore_corrupt = True(mount_mode & OrbisSaveDataMountMode::DESTRUCT_OFF);
const bool ignore_corrupt =
True(mount_mode & OrbisSaveDataMountMode::DESTRUCT_OFF) || g_fw_ver < ElfInfo::FW_16;
const std::string_view dir_name{mount_info->dirName->data}; const std::string_view dir_name{mount_info->dirName->data};
@ -436,9 +459,11 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
mount_result->mount_point.data.FromString(save_instance.GetMountPoint()); mount_result->mount_point.data.FromString(save_instance.GetMountPoint());
mount_result->mount_status = create_if_not_exist && to_be_created if (g_fw_ver >= ElfInfo::FW_45) {
? OrbisSaveDataMountStatus::CREATED mount_result->mount_status = create_if_not_exist && to_be_created
: OrbisSaveDataMountStatus::NOTHING; ? OrbisSaveDataMountStatus::CREATED
: OrbisSaveDataMountStatus::NOTHING;
}
g_mount_slots[slot_num].emplace(std::move(save_instance)); g_mount_slots[slot_num].emplace(std::move(save_instance));
@ -448,7 +473,7 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
static Error Umount(const OrbisSaveDataMountPoint* mountPoint, bool call_backup = false) { static Error Umount(const OrbisSaveDataMountPoint* mountPoint, bool call_backup = false) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (mountPoint == nullptr) { if (mountPoint == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -501,7 +526,7 @@ int PS4_SYSV_ABI sceSaveDataAbort() {
Error PS4_SYSV_ABI sceSaveDataBackup(const OrbisSaveDataBackup* backup) { Error PS4_SYSV_ABI sceSaveDataBackup(const OrbisSaveDataBackup* backup) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (backup == nullptr || backup->dirName == nullptr) { if (backup == nullptr || backup->dirName == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -550,7 +575,7 @@ int PS4_SYSV_ABI sceSaveDataChangeInternal() {
Error PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData* check) { Error PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData* check) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (check == nullptr || check->dirName == nullptr) { if (check == nullptr || check->dirName == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -635,7 +660,7 @@ int PS4_SYSV_ABI sceSaveDataCheckSaveDataVersionLatest() {
Error PS4_SYSV_ABI sceSaveDataClearProgress() { Error PS4_SYSV_ABI sceSaveDataClearProgress() {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
LOG_DEBUG(Lib_SaveData, "called"); LOG_DEBUG(Lib_SaveData, "called");
Backup::ClearProgress(); Backup::ClearProgress();
@ -690,7 +715,7 @@ int PS4_SYSV_ABI sceSaveDataDebugTarget() {
Error PS4_SYSV_ABI sceSaveDataDelete(const OrbisSaveDataDelete* del) { Error PS4_SYSV_ABI sceSaveDataDelete(const OrbisSaveDataDelete* del) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (del == nullptr) { if (del == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -742,7 +767,7 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
OrbisSaveDataDirNameSearchResult* result) { OrbisSaveDataDirNameSearchResult* result) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (cond == nullptr || result == nullptr || cond->key > OrbisSaveDataSortKey::FREE_BLOCKS || if (cond == nullptr || result == nullptr || cond->key > OrbisSaveDataSortKey::FREE_BLOCKS ||
cond->order > OrbisSaveDataSortOrder::DESCENT) { cond->order > OrbisSaveDataSortOrder::DESCENT) {
@ -757,7 +782,9 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
if (!fs::exists(save_path)) { if (!fs::exists(save_path)) {
result->hitNum = 0; result->hitNum = 0;
result->setNum = 0; if (g_fw_ver >= ElfInfo::FW_17) {
result->setNum = 0;
}
return Error::OK; return Error::OK;
} }
@ -825,21 +852,25 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
std::ranges::reverse(dir_list); std::ranges::reverse(dir_list);
} }
result->hitNum = dir_list.size();
size_t max_count = std::min(static_cast<size_t>(result->dirNamesNum), dir_list.size()); size_t max_count = std::min(static_cast<size_t>(result->dirNamesNum), dir_list.size());
result->setNum = max_count; if (g_fw_ver >= ElfInfo::FW_17) {
result->hitNum = dir_list.size();
result->setNum = max_count;
} else {
result->hitNum = max_count;
}
for (size_t i = 0; i < max_count; i++) { for (size_t i = 0; i < max_count; i++) {
auto& name_data = result->dirNames[i].data; auto& name_data = result->dirNames[i].data;
name_data.FromString(dir_list[i]); name_data.FromString(dir_list[i]);
if (result->params != nullptr) { if (g_fw_ver >= ElfInfo::FW_17 && result->params != nullptr) {
auto& sfo = map_dir_sfo.at(dir_list[i]); auto& sfo = map_dir_sfo.at(dir_list[i]);
auto& param_data = result->params[i]; auto& param_data = result->params[i];
param_data.FromSFO(sfo); param_data.FromSFO(sfo);
} }
if (result->infos != nullptr) { if (g_fw_ver >= ElfInfo::FW_25 && result->infos != nullptr) {
auto& info = result->infos[i]; auto& info = result->infos[i];
info.blocks = map_max_blocks.at(dir_list[i]); info.blocks = map_max_blocks.at(dir_list[i]);
info.freeBlocks = map_free_size.at(dir_list[i]); info.freeBlocks = map_free_size.at(dir_list[i]);
@ -913,7 +944,7 @@ Error PS4_SYSV_ABI sceSaveDataGetEventResult(const OrbisSaveDataEventParam*,
OrbisSaveDataEvent* event) { OrbisSaveDataEvent* event) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (event == nullptr) { if (event == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -949,7 +980,7 @@ Error PS4_SYSV_ABI sceSaveDataGetMountInfo(const OrbisSaveDataMountPoint* mountP
OrbisSaveDataMountInfo* info) { OrbisSaveDataMountInfo* info) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (mountPoint == nullptr || info == nullptr) { if (mountPoint == nullptr || info == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -974,7 +1005,7 @@ Error PS4_SYSV_ABI sceSaveDataGetParam(const OrbisSaveDataMountPoint* mountPoint
size_t paramBufSize, size_t* gotSize) { size_t paramBufSize, size_t* gotSize) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (paramType > OrbisSaveDataParamType::MTIME || paramBuf == nullptr) { if (paramType > OrbisSaveDataParamType::MTIME || paramBuf == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1049,7 +1080,7 @@ Error PS4_SYSV_ABI sceSaveDataGetParam(const OrbisSaveDataMountPoint* mountPoint
Error PS4_SYSV_ABI sceSaveDataGetProgress(float* progress) { Error PS4_SYSV_ABI sceSaveDataGetProgress(float* progress) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (progress == nullptr) { if (progress == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1083,7 +1114,7 @@ Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const OrbisUserServiceUserId use
Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam) { Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (getParam == nullptr) { if (getParam == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1179,7 +1210,7 @@ Error PS4_SYSV_ABI sceSaveDataLoadIcon(const OrbisSaveDataMountPoint* mountPoint
OrbisSaveDataIcon* icon) { OrbisSaveDataIcon* icon) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (mountPoint == nullptr || icon == nullptr || icon->buf == nullptr) { if (mountPoint == nullptr || icon == nullptr || icon->buf == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1208,7 +1239,7 @@ Error PS4_SYSV_ABI sceSaveDataMount(const OrbisSaveDataMount* mount,
OrbisSaveDataMountResult* mount_result) { OrbisSaveDataMountResult* mount_result) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (mount == nullptr && mount->dirName != nullptr) { if (mount == nullptr && mount->dirName != nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1229,7 +1260,7 @@ Error PS4_SYSV_ABI sceSaveDataMount2(const OrbisSaveDataMount2* mount,
OrbisSaveDataMountResult* mount_result) { OrbisSaveDataMountResult* mount_result) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (mount == nullptr && mount->dirName != nullptr) { if (mount == nullptr && mount->dirName != nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1273,7 +1304,7 @@ int PS4_SYSV_ABI sceSaveDataRegisterEventCallback() {
Error PS4_SYSV_ABI sceSaveDataRestoreBackupData(const OrbisSaveDataRestoreBackupData* restore) { Error PS4_SYSV_ABI sceSaveDataRestoreBackupData(const OrbisSaveDataRestoreBackupData* restore) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (restore == nullptr || restore->dirName == nullptr) { if (restore == nullptr || restore->dirName == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1324,7 +1355,7 @@ Error PS4_SYSV_ABI sceSaveDataSaveIcon(const OrbisSaveDataMountPoint* mountPoint
const OrbisSaveDataIcon* icon) { const OrbisSaveDataIcon* icon) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (mountPoint == nullptr || icon == nullptr || icon->buf == nullptr) { if (mountPoint == nullptr || icon == nullptr || icon->buf == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1372,7 +1403,7 @@ Error PS4_SYSV_ABI sceSaveDataSetParam(const OrbisSaveDataMountPoint* mountPoint
size_t paramBufSize) { size_t paramBufSize) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (paramType > OrbisSaveDataParamType::USER_PARAM || mountPoint == nullptr || if (paramType > OrbisSaveDataParamType::USER_PARAM || mountPoint == nullptr ||
paramBuf == nullptr) { paramBuf == nullptr) {
@ -1437,13 +1468,15 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(OrbisUserServiceUserId userId, v
OrbisSaveDataMemorySet2 setParam{}; OrbisSaveDataMemorySet2 setParam{};
setParam.userId = userId; setParam.userId = userId;
setParam.data = &data; setParam.data = &data;
setParam.param = nullptr;
setParam.icon = nullptr;
return sceSaveDataSetSaveDataMemory2(&setParam); return sceSaveDataSetSaveDataMemory2(&setParam);
} }
Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam) { Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (setParam == nullptr) { if (setParam == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1476,17 +1509,35 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2*
return Error::OK; return Error::OK;
} }
int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(/*u32 userId, size_t memorySize, Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(OrbisUserServiceUserId userId, size_t memorySize,
OrbisSaveDataParam* param*/) { OrbisSaveDataParam* param) {
LOG_ERROR(Lib_SaveData, "(STUBBED) called"); LOG_DEBUG(Lib_SaveData, "called: userId = {}, memorySize = {}", userId, memorySize);
return ORBIS_OK; OrbisSaveDataMemorySetup2 setupParam{};
setupParam.userId = userId;
setupParam.memorySize = memorySize;
setupParam.initParam = nullptr;
setupParam.initIcon = nullptr;
OrbisSaveDataMemorySetupResult result{};
const auto res = sceSaveDataSetupSaveDataMemory2(&setupParam, &result);
if (res != Error::OK) {
return res;
}
if (param != nullptr) {
OrbisSaveDataMemorySet2 setParam{};
setParam.userId = userId;
setParam.data = nullptr;
setParam.param = param;
setParam.icon = nullptr;
sceSaveDataSetSaveDataMemory2(&setParam);
}
return Error::OK;
} }
Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2* setupParam, Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2* setupParam,
OrbisSaveDataMemorySetupResult* result) { OrbisSaveDataMemorySetupResult* result) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (setupParam == nullptr) { if (setupParam == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1506,20 +1557,20 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
try { try {
size_t existed_size = SaveMemory::CreateSaveMemory(setupParam->memorySize); size_t existed_size = SaveMemory::CreateSaveMemory(setupParam->memorySize);
if (existed_size == 0) { // Just created if (existed_size == 0) { // Just created
if (setupParam->initParam != nullptr) { if (g_fw_ver >= ElfInfo::FW_45 && setupParam->initParam != nullptr) {
auto& sfo = SaveMemory::GetParamSFO(); auto& sfo = SaveMemory::GetParamSFO();
setupParam->initParam->ToSFO(sfo); setupParam->initParam->ToSFO(sfo);
} }
SaveMemory::SaveSFO(); SaveMemory::SaveSFO();
auto init_icon = setupParam->initIcon; auto init_icon = setupParam->initIcon;
if (init_icon != nullptr) { if (g_fw_ver >= ElfInfo::FW_45 && init_icon != nullptr) {
SaveMemory::SetIcon(init_icon->buf, init_icon->bufSize); SaveMemory::SetIcon(init_icon->buf, init_icon->bufSize);
} else { } else {
SaveMemory::SetIcon(nullptr, 0); SaveMemory::SetIcon(nullptr, 0);
} }
} }
if (result != nullptr) { if (g_fw_ver >= ElfInfo::FW_45 && result != nullptr) {
result->existedMemorySize = existed_size; result->existedMemorySize = existed_size;
} }
} catch (const fs::filesystem_error& e) { } catch (const fs::filesystem_error& e) {
@ -1555,7 +1606,7 @@ int PS4_SYSV_ABI sceSaveDataSyncCloudList() {
Error PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncParam) { Error PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncParam) {
if (!g_initialized) { if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize"); LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
if (syncParam == nullptr) { if (syncParam == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter"); LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1576,11 +1627,15 @@ Error PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncPa
Error PS4_SYSV_ABI sceSaveDataTerminate() { Error PS4_SYSV_ABI sceSaveDataTerminate() {
LOG_DEBUG(Lib_SaveData, "called"); LOG_DEBUG(Lib_SaveData, "called");
if (!g_initialized) { if (!g_initialized) {
return Error::NOT_INITIALIZED; return setNotInitializedError();
} }
for (const auto& instance : g_mount_slots) { for (auto& instance : g_mount_slots) {
if (instance.has_value()) { if (instance.has_value()) {
return Error::BUSY; if (g_fw_ver >= ElfInfo::FW_40) {
return Error::BUSY;
}
instance->Umount();
instance.reset();
} }
} }
g_initialized = false; g_initialized = false;

View File

@ -165,8 +165,8 @@ int PS4_SYSV_ABI sceSaveDataSetSaveDataLibraryUser();
Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(OrbisUserServiceUserId userId, void* buf, Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(OrbisUserServiceUserId userId, void* buf,
size_t bufSize, int64_t offset); size_t bufSize, int64_t offset);
Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam); Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam);
int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(/*u32 userId, size_t memorySize, Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(OrbisUserServiceUserId userId, size_t memorySize,
OrbisSaveDataParam* param*/); OrbisSaveDataParam* param);
Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2* setupParam, Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2* setupParam,
OrbisSaveDataMemorySetupResult* result); OrbisSaveDataMemorySetupResult* result);
int PS4_SYSV_ABI sceSaveDataShutdownStart(); int PS4_SYSV_ABI sceSaveDataShutdownStart();