From 0ecc54032c0ba395c02b9728bc5e9ec48ef65071 Mon Sep 17 00:00:00 2001 From: raziel1000 Date: Thu, 4 Jul 2024 01:51:46 -0600 Subject: [PATCH] - Several SaveData functions. Dysmantle and we are doomed should save and load now. --- src/core/file_sys/fs.cpp | 7 +- src/core/file_sys/fs.h | 2 +- src/core/libraries/kernel/file_system.cpp | 3 +- src/core/libraries/save_data/error_codes.h | 26 +- src/core/libraries/save_data/savedata.cpp | 313 ++++++++++++++++----- src/core/libraries/save_data/savedata.h | 226 +++++++++++++-- src/emulator.cpp | 3 + 7 files changed, 488 insertions(+), 92 deletions(-) diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp index 912c74bf..a1c03d89 100644 --- a/src/core/file_sys/fs.cpp +++ b/src/core/file_sys/fs.cpp @@ -18,7 +18,12 @@ void MntPoints::Mount(const std::filesystem::path& host_folder, const std::strin m_mnt_pairs.push_back(pair); } -void MntPoints::Unmount(const std::string& path) {} // TODO! +void MntPoints::Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder) { + auto it = std::remove_if(m_mnt_pairs.begin(), m_mnt_pairs.end(), [&](const MntPair& pair) { + return pair.guest_path == guest_folder; + }); + m_mnt_pairs.erase(it, m_mnt_pairs.end()); +} void MntPoints::UnmountAll() { std::scoped_lock lock{m_mutex}; diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index 4ba01685..b31931d1 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -22,7 +22,7 @@ public: virtual ~MntPoints() = default; void Mount(const std::filesystem::path& host_folder, const std::string& guest_folder); - void Unmount(const std::string& path); + void Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder); void UnmountAll(); std::string GetHostDirectory(const std::string& guest_directory); std::string GetHostFile(const std::string& guest_file); diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index c3b6c3ae..b58555d5 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -227,7 +227,8 @@ int PS4_SYSV_ABI sceKernelMkdir(const char* path, u16 mode) { return SCE_KERNEL_ERROR_EEXIST; } - if (!std::filesystem::create_directory(dir_name)) { + //CUSA02456: path = /aotl after sceSaveDataMount(mode = 1) + if (dir_name.empty() || !std::filesystem::create_directory(dir_name)) { return SCE_KERNEL_ERROR_EIO; } diff --git a/src/core/libraries/save_data/error_codes.h b/src/core/libraries/save_data/error_codes.h index 0dfe9def..a4a1b7a5 100644 --- a/src/core/libraries/save_data/error_codes.h +++ b/src/core/libraries/save_data/error_codes.h @@ -3,6 +3,26 @@ #pragma once -constexpr int ORBIS_SAVE_DATA_ERROR_PARAMETER = 0x809f0000; -constexpr int ORBIS_SAVE_DATA_ERROR_NOT_FOUND = 0x809f0008; // save data doesn't exist -constexpr int ORBIS_SAVE_DATA_ERROR_EXISTS = 0x809f0007; // save data directory,same name exists \ No newline at end of file +constexpr int ORBIS_SAVE_DATA_ERROR_PARAMETER = 0x809F0000; +constexpr int ORBIS_SAVE_DATA_ERROR_NOT_INITIALIZED = 0x809F0001; +constexpr int ORBIS_SAVE_DATA_ERROR_OUT_OF_MEMORY = 0x809F0002; +constexpr int ORBIS_SAVE_DATA_ERROR_BUSY = 0x809F0003; +constexpr int ORBIS_SAVE_DATA_ERROR_NOT_MOUNTED = 0x809F0004; +constexpr int ORBIS_SAVE_DATA_ERROR_NO_PERMISSION = 0x809F0005; +constexpr int ORBIS_SAVE_DATA_ERROR_FINGERPRINT_MISMATCH = 0x809F0006; +constexpr int ORBIS_SAVE_DATA_ERROR_EXISTS = 0x809F0007; +constexpr int ORBIS_SAVE_DATA_ERROR_NOT_FOUND = 0x809F0008; +constexpr int ORBIS_SAVE_DATA_ERROR_NO_SPACE_FS = 0x809F000A; +constexpr int ORBIS_SAVE_DATA_ERROR_INTERNAL = 0x809F000B; +constexpr int ORBIS_SAVE_DATA_ERROR_MOUNT_FULL = 0x809F000C; +constexpr int ORBIS_SAVE_DATA_ERROR_BAD_MOUNTED = 0x809F000D; +constexpr int ORBIS_SAVE_DATA_ERROR_FILE_NOT_FOUND = 0x809F000E; +constexpr int ORBIS_SAVE_DATA_ERROR_BROKEN = 0x809F000F; +constexpr int ORBIS_SAVE_DATA_ERROR_INVALID_LOGIN_USER = 0x809F0011; +constexpr int ORBIS_SAVE_DATA_ERROR_MEMORY_NOT_READY = 0x809F0012; +constexpr int ORBIS_SAVE_DATA_ERROR_BACKUP_BUSY = 0x809F0013; +constexpr int ORBIS_SAVE_DATA_ERROR_NOT_REGIST_CALLBACK = 0x809F0015; +constexpr int ORBIS_SAVE_DATA_ERROR_BUSY_FOR_SAVING = 0x809F0016; +constexpr int ORBIS_SAVE_DATA_ERROR_LIMITATION_OVER = 0x809F0017; +constexpr int ORBIS_SAVE_DATA_ERROR_EVENT_BUSY = 0x809F0018; +constexpr int ORBIS_SAVE_DATA_ERROR_PARAMSFO_TRANSFER_TITLE_ID_NOT_FOUND = 0x809F0019; diff --git a/src/core/libraries/save_data/savedata.cpp b/src/core/libraries/save_data/savedata.cpp index d4f04a25..68bb5566 100644 --- a/src/core/libraries/save_data/savedata.cpp +++ b/src/core/libraries/save_data/savedata.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include #include #include #include @@ -13,8 +15,8 @@ #include "error_codes.h" namespace Libraries::SaveData { - static std::string g_mount_point = "/savedata0"; // temp mount point (todo) +std::string game_serial; int PS4_SYSV_ABI sceSaveDataAbort() { LOG_ERROR(Lib_SaveData, "(STUBBED) called"); @@ -46,8 +48,14 @@ int PS4_SYSV_ABI sceSaveDataChangeInternal() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataCheckBackupData() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData* check) { + auto* mnt = Common::Singleton::Instance(); + std::string mount_dir = mnt->GetHostFile(check->dirName->data); + if (!std::filesystem::exists(mount_dir)) { + return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; + } + LOG_INFO(Lib_SaveData, "called = {}", mount_dir); + return ORBIS_OK; } @@ -136,8 +144,14 @@ int PS4_SYSV_ABI sceSaveDataDebugTarget() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataDelete() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataDelete(const OrbisSaveDataDelete* del) { + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(1) / game_serial / std::string(del->dirName->data); + LOG_INFO(Lib_SaveData, "called: dirname = {}, mount_dir = {}", (char*)del->dirName->data, + mount_dir.string()); + if (std::filesystem::exists(mount_dir) && std::filesystem::is_directory(mount_dir)) { + std::filesystem::remove_all(mount_dir); + } return ORBIS_OK; } @@ -161,8 +175,14 @@ int PS4_SYSV_ABI sceSaveDataDeleteUser() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataDirNameSearch() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond* cond, + OrbisSaveDataDirNameSearchResult* result) { + if (cond == nullptr || cond->dirName == nullptr) + return ORBIS_SAVE_DATA_ERROR_PARAMETER; + LOG_ERROR(Lib_SaveData, + "TODO sceSaveDataDirNameSearch: search_dir_name = {}, key = {}, result = {}", + cond->dirName->data, (int)cond->key, (result->infos == nullptr)); + return ORBIS_OK; } @@ -226,8 +246,22 @@ int PS4_SYSV_ABI sceSaveDataGetEventInfo() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataGetEventResult() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataGetEventResult(const OrbisSaveDataEventParam* eventParam, + OrbisSaveDataEvent* event) { + LOG_INFO(Lib_SaveData, "called sceSaveDataGetEventResult : null = {}", (eventParam == nullptr)); + if (eventParam == nullptr) + return ORBIS_SAVE_DATA_ERROR_PARAMETER; + + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(1) / game_serial; // fix me + + Common::FS::IOFile file(mount_dir / "param.txt", Common::FS::FileAccessMode::Read); + OrbisSaveDataParam* param = new OrbisSaveDataParam{}; + file.ReadRaw(param, sizeof(OrbisSaveDataParam)); + + LOG_INFO(Lib_SaveData, "called"); + event->userId = 1; + return ORBIS_OK; } @@ -241,8 +275,11 @@ int PS4_SYSV_ABI sceSaveDataGetMountedSaveDataCount() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataGetMountInfo() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataGetMountInfo(const OrbisSaveDataMountPoint* mountPoint, + OrbisSaveDataMountInfo* info) { + LOG_INFO(Lib_SaveData, "called"); + info->blocks = ORBIS_SAVE_DATA_BLOCKS_MAX; + info->freeBlocks = ORBIS_SAVE_DATA_BLOCKS_MAX; return ORBIS_OK; } @@ -261,13 +298,43 @@ int PS4_SYSV_ABI sceSaveDataGetSaveDataCount() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const u32 userId, void* buf, const size_t bufSize, + const int64_t offset) { + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(userId) / game_serial / "save_mem1.sav"; + + Common::FS::IOFile file(mount_dir, Common::FS::FileAccessMode::Read); + if (!file.IsOpen()) { + return false; + } + file.Seek(offset); + size_t nbytes = file.ReadRaw(buf, bufSize); + LOG_INFO(Lib_SaveData, "called: bufSize = {}, offset = {}", bufSize, offset, nbytes); + return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam) { + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(getParam->userId) / game_serial; + if (getParam == nullptr) + return ORBIS_SAVE_DATA_ERROR_PARAMETER; + if (getParam->data != nullptr) { + Common::FS::IOFile file(mount_dir / "save_mem2.sav", Common::FS::FileAccessMode::Read); + if (!file.IsOpen()) { + return false; + } + file.Seek(getParam->data->offset); + size_t nbytes = file.ReadRaw(getParam->data->buf, getParam->data->bufSize); + LOG_INFO(Lib_SaveData, "called: bufSize = {}, offset = {}", getParam->data->bufSize, + getParam->data->offset); + } + + if (getParam->param != nullptr) { + Common::FS::IOFile file1(mount_dir / "param.txt", Common::FS::FileAccessMode::Read); + size_t nbytes = file1.ReadRaw(getParam->param, sizeof(OrbisSaveDataParam)); + } + return ORBIS_OK; } @@ -297,17 +364,23 @@ int PS4_SYSV_ABI sceSaveDataGetUpdatedDataCount() { } int PS4_SYSV_ABI sceSaveDataInitialize() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); + LOG_INFO(Lib_SaveData, "called"); + static auto* param_sfo = Common::Singleton::Instance(); + game_serial = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9); return ORBIS_OK; } int PS4_SYSV_ABI sceSaveDataInitialize2() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); + LOG_INFO(Lib_SaveData, "called"); + static auto* param_sfo = Common::Singleton::Instance(); + game_serial = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9); return ORBIS_OK; } int PS4_SYSV_ABI sceSaveDataInitialize3() { - LOG_ERROR(Lib_SaveData, "(DUMMY) called"); + LOG_INFO(Lib_SaveData, "called"); + static auto* param_sfo = Common::Singleton::Instance(); + game_serial = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9); return ORBIS_OK; } @@ -326,18 +399,24 @@ int PS4_SYSV_ABI sceSaveDataIsMounted() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataLoadIcon() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataLoadIcon(const OrbisSaveDataMountPoint* mountPoint, + OrbisSaveDataIcon* icon) { + auto* mnt = Common::Singleton::Instance(); + std::string mount_dir = mnt->GetHostFile(mountPoint->data); + LOG_INFO(Lib_SaveData, "called: dir = {}", mount_dir); + + if (icon != nullptr) { + Common::FS::IOFile file(mount_dir + "/save_data.png", Common::FS::FileAccessMode::Read); + icon->bufSize = file.GetSize(); + size_t nbytes = file.ReadRaw(icon->buf, icon->bufSize); + } return ORBIS_OK; } -s32 saveDataMount(u32 user_id, std::string dir_name, u32 mount_mode, +s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode, OrbisSaveDataMountResult* mount_result) { - - auto* param_sfo = Common::Singleton::Instance(); - std::string id(param_sfo->GetString("CONTENT_ID"), 7, 9); const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / - std::to_string(user_id) / "savedata" / id / dir_name; + std::to_string(user_id) / game_serial / dir_name; switch (mount_mode) { case ORBIS_SAVE_DATA_MOUNT_MODE_RDONLY: case ORBIS_SAVE_DATA_MOUNT_MODE_RDWR: @@ -346,10 +425,9 @@ s32 saveDataMount(u32 user_id, std::string dir_name, u32 mount_mode, return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; } auto* mnt = Common::Singleton::Instance(); - mnt->Mount(mount_dir, g_mount_point); - mount_result->mount_status = 0; - strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + mnt->Mount(mount_dir, mount_result->mount_point.data); } break; case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE: case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE | ORBIS_SAVE_DATA_MOUNT_MODE_RDONLY: @@ -357,17 +435,22 @@ s32 saveDataMount(u32 user_id, std::string dir_name, u32 mount_mode, case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE | ORBIS_SAVE_DATA_MOUNT_MODE_RDWR | ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE | ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF | - ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: { + ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: + case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE | ORBIS_SAVE_DATA_MOUNT_MODE_RDWR | + ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF: { + auto* mnt = Common::Singleton::Instance(); if (std::filesystem::exists(mount_dir)) { + std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + mnt->Mount(mount_dir, mount_result->mount_point.data); + mount_result->required_blocks = 0; + mount_result->mount_status = 0; return ORBIS_SAVE_DATA_ERROR_EXISTS; } - std::filesystem::create_directories(mount_dir); - - auto* mnt = Common::Singleton::Instance(); - mnt->Mount(mount_dir, g_mount_point); - - mount_result->mount_status = 1; - strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + if (std::filesystem::create_directories(mount_dir)) { + std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + mnt->Mount(mount_dir, mount_result->mount_point.data); + mount_result->mount_status = 1; + } } break; case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE2 | ORBIS_SAVE_DATA_MOUNT_MODE_RDWR: case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE2 | ORBIS_SAVE_DATA_MOUNT_MODE_RDWR | @@ -375,12 +458,10 @@ s32 saveDataMount(u32 user_id, std::string dir_name, u32 mount_mode, if (!std::filesystem::exists(mount_dir)) { std::filesystem::create_directories(mount_dir); } - auto* mnt = Common::Singleton::Instance(); - mnt->Mount(mount_dir, g_mount_point); - + std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + mnt->Mount(mount_dir, mount_result->mount_point.data); mount_result->mount_status = 1; - strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); } break; default: UNREACHABLE(); @@ -395,9 +476,9 @@ s32 PS4_SYSV_ABI sceSaveDataMount(const OrbisSaveDataMount* mount, if (mount == nullptr) { return ORBIS_SAVE_DATA_ERROR_PARAMETER; } - LOG_INFO(Lib_SaveData, "called: mount = {}, mode = {}, blocks = {}", mount->dir_name->data, + LOG_INFO(Lib_SaveData, "called: dirName = {}, mode = {}, blocks = {}", mount->dir_name->data, mount->mount_mode, mount->blocks); - return saveDataMount(mount->user_id, std::string(mount->dir_name->data), mount->mount_mode, + return saveDataMount(mount->user_id, (char*)mount->dir_name->data, mount->mount_mode, mount_result); } @@ -406,9 +487,9 @@ s32 PS4_SYSV_ABI sceSaveDataMount2(const OrbisSaveDataMount2* mount, if (mount == nullptr) { return ORBIS_SAVE_DATA_ERROR_PARAMETER; } - LOG_INFO(Lib_SaveData, "called: mount = {}, mode = {}, blocks = {}", mount->dir_name->data, + LOG_INFO(Lib_SaveData, "called: dirName = {}, mode = {}, blocks = {}", mount->dir_name->data, mount->mount_mode, mount->blocks); - return saveDataMount(mount->user_id, std::string(mount->dir_name->data), mount->mount_mode, + return saveDataMount(mount->user_id, (char*)mount->dir_name->data, mount->mount_mode, mount_result); } @@ -457,8 +538,16 @@ int PS4_SYSV_ABI sceSaveDataRestoreLoadSaveDataMemory() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataSaveIcon() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataSaveIcon(const OrbisSaveDataMountPoint* mountPoint, + const OrbisSaveDataIcon* icon) { + auto* mnt = Common::Singleton::Instance(); + std::string mount_dir = mnt->GetHostFile(mountPoint->data); + LOG_INFO(Lib_SaveData, "called = {}", mount_dir); + + if (icon != nullptr) { + Common::FS::IOFile file(mount_dir + "/save_data.png", Common::FS::FileAccessMode::Write); + file.WriteRaw((void*)icon->buf, icon->bufSize); + } return ORBIS_OK; } @@ -472,8 +561,17 @@ int PS4_SYSV_ABI sceSaveDataSetEventInfo() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataSetParam() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataSetParam(const OrbisSaveDataMountPoint* mountPoint, + OrbisSaveDataParamType paramType, const void* paramBuf, + size_t paramBufSize) { + auto* mnt = Common::Singleton::Instance(); + std::string mount_dir = mnt->GetHostFile(mountPoint->data); + LOG_INFO(Lib_SaveData, "called = {}, mountPoint->data = {}", mount_dir, mountPoint->data); + + if (paramBuf != nullptr) { + Common::FS::IOFile file(mount_dir + "/param.txt", Common::FS::FileAccessMode::Write); + file.WriteRaw((void*)paramBuf, paramBufSize); + } return ORBIS_OK; } @@ -482,23 +580,89 @@ int PS4_SYSV_ABI sceSaveDataSetSaveDataLibraryUser() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(const u32 userId, const void* buf, + const size_t bufSize, const int64_t offset) { + LOG_INFO(Lib_SaveData, "called"); + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(userId) / game_serial / "save_mem1.sav"; + + Common::FS::IOFile file(mount_dir, Common::FS::FileAccessMode::Write); + file.Seek(offset); + file.WriteRaw((void*)buf, bufSize); + return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam) { + LOG_INFO(Lib_SaveData, "called: dataNum = {}, slotId= {}", setParam->dataNum, setParam->slotId); + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(setParam->userId) / game_serial; + if (setParam->data != nullptr) { + Common::FS::IOFile file(mount_dir / "save_mem2.sav", Common::FS::FileAccessMode::Write); + if (!file.IsOpen()) + return -1; + file.Seek(setParam->data->offset); + file.WriteRaw((void*)setParam->data->buf, setParam->data->bufSize); + } + + if (setParam->param != nullptr) { + Common::FS::IOFile file(mount_dir / "param.txt", Common::FS::FileAccessMode::Write); + file.WriteRaw((void*)setParam->param, sizeof(OrbisSaveDataParam)); + } + + if (setParam->icon != nullptr) { + Common::FS::IOFile file(mount_dir / "save_icon.png", Common::FS::FileAccessMode::Write); + file.WriteRaw((void*)setParam->icon->buf, setParam->icon->bufSize); + } + return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(u32 userId, size_t memorySize, + OrbisSaveDataParam* param) { + + LOG_INFO(Lib_SaveData, "called:userId = {}, memorySize = {}", userId, memorySize); + + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(userId) / game_serial; + + if (std::filesystem::exists(mount_dir)) { + return ORBIS_SAVE_DATA_ERROR_EXISTS; + } + std::filesystem::create_directories(mount_dir); + std::vector buf(memorySize); + Common::FS::IOFile::WriteBytes(mount_dir / "save_mem1.sav", buf); return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2* setupParam, + OrbisSaveDataMemorySetupResult* result) { + if (setupParam == nullptr) { + return ORBIS_SAVE_DATA_ERROR_PARAMETER; + } + LOG_INFO(Lib_SaveData, "called"); + // if (setupParam->option == 1) { // check this later. + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(setupParam->userId) / game_serial; + if (std::filesystem::exists(mount_dir) && + std::filesystem::exists(mount_dir / "save_mem2.sav")) { + Common::FS::IOFile file(mount_dir / "save_mem2.sav", Common::FS::FileAccessMode::Read); + if (!file.IsOpen()) + return -1; + // Bunny - CUSA07988 has a null result, having null result is checked and valid. + if (result != nullptr) + result->existedMemorySize = file.GetSize(); // Assign the saved data size. + // do not return ORBIS_SAVE_DATA_ERROR_EXISTS, as it will not trigger + // sceSaveDataGetSaveDataMemory2. + } else { + std::filesystem::create_directories(mount_dir); + std::vector buf(setupParam->memorySize); // check if > 0x1000000 (16.77mb) or x2? + Common::FS::IOFile::WriteBytes(mount_dir / "save_mem2.sav", buf); + std::vector paramBuf(sizeof(OrbisSaveDataParam)); + Common::FS::IOFile::WriteBytes(mount_dir / "param.txt", paramBuf); + std::vector iconBuf(setupParam->iconMemorySize); + Common::FS::IOFile::WriteBytes(mount_dir / "save_icon.png", iconBuf); + } return ORBIS_OK; } @@ -517,8 +681,8 @@ int PS4_SYSV_ABI sceSaveDataSyncCloudList() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncParam) { + LOG_ERROR(Lib_SaveData, "(STUBBED) called: option = {}", syncParam->option); return ORBIS_OK; } @@ -533,12 +697,16 @@ int PS4_SYSV_ABI sceSaveDataTransferringMount() { } s32 PS4_SYSV_ABI sceSaveDataUmount(const OrbisSaveDataMountPoint* mountPoint) { - LOG_INFO(Lib_SaveData, "mountPoint = {}", std::string(mountPoint->data)); if (std::string(mountPoint->data).empty()) { - return ORBIS_SAVE_DATA_ERROR_PARAMETER; + return ORBIS_SAVE_DATA_ERROR_NOT_MOUNTED; } + const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / + std::to_string(1) / game_serial / mountPoint->data; auto* mnt = Common::Singleton::Instance(); - mnt->Unmount(std::string(mountPoint->data)); + + mnt->Unmount(mount_dir, mountPoint->data); + LOG_INFO(Lib_SaveData, "mountPoint = {}", std::string(mountPoint->data)); + return ORBIS_OK; } @@ -547,8 +715,27 @@ int PS4_SYSV_ABI sceSaveDataUmountSys() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSaveDataUmountWithBackup() { - LOG_ERROR(Lib_SaveData, "(STUBBED) called"); +int PS4_SYSV_ABI sceSaveDataUmountWithBackup(const OrbisSaveDataMountPoint* mountPoint) { + LOG_ERROR(Lib_SaveData, "called = {}", std::string(mountPoint->data)); + auto* mnt = Common::Singleton::Instance(); + std::string mount_dir = mnt->GetHostFile(mountPoint->data); + if (!std::filesystem::exists(mount_dir)) { + return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; + } else { + std::filesystem::path mnt_dir(mount_dir); + std::filesystem::create_directories(mnt_dir.parent_path() / "backup"); + + for (const auto& entry : std::filesystem::recursive_directory_iterator(mnt_dir)) { + const auto& path = entry.path(); + std::filesystem::path target_path = mnt_dir.parent_path() / "backup"; + + if (std::filesystem::is_regular_file(path)) { + std::filesystem::copy(path, target_path, + std::filesystem::copy_options::overwrite_existing); + } + } + mnt->Unmount(mount_dir, mountPoint->data); + } return ORBIS_OK; } diff --git a/src/core/libraries/save_data/savedata.h b/src/core/libraries/save_data/savedata.h index 60f99cea..dbfbd320 100644 --- a/src/core/libraries/save_data/savedata.h +++ b/src/core/libraries/save_data/savedata.h @@ -43,19 +43,18 @@ struct OrbisSaveDataMountResult { }; constexpr int ORBIS_SAVE_DATA_TITLE_ID_DATA_SIZE = 10; -typedef struct OrbisSaveDataTitleId { +struct OrbisSaveDataTitleId { char data[ORBIS_SAVE_DATA_TITLE_ID_DATA_SIZE]; char padding[6]; - -} OrbisSaveDataTitleId; +}; constexpr int ORBIS_SAVE_DATA_FINGERPRINT_DATA_SIZE = 65; -typedef struct OrbisSaveDataFingerprint { +struct OrbisSaveDataFingerprint { char data[ORBIS_SAVE_DATA_FINGERPRINT_DATA_SIZE]; char padding[15]; -} OrbisSaveDataFingerprint; +}; -typedef struct OrbisSaveDataMount { +struct OrbisSaveDataMount { s32 user_id; s32 pad; const OrbisSaveDataTitleId* titleId; @@ -64,7 +63,114 @@ typedef struct OrbisSaveDataMount { u64 blocks; u32 mount_mode; u8 reserved[32]; -} OrbisSaveDataMount; +}; + +typedef u32 OrbisSaveDataParamType; + +constexpr int ORBIS_SAVE_DATA_TITLE_MAXSIZE = 128; +constexpr int ORBIS_SAVE_DATA_SUBTITLE_MAXSIZE = 128; +constexpr int ORBIS_SAVE_DATA_DETAIL_MAXSIZE = 1024; +struct OrbisSaveDataParam { + char title[ORBIS_SAVE_DATA_TITLE_MAXSIZE]; + char subTitle[ORBIS_SAVE_DATA_SUBTITLE_MAXSIZE]; + char detail[ORBIS_SAVE_DATA_DETAIL_MAXSIZE]; + u32 userParam; + int : 32; + time_t mtime; + u8 reserved[32]; +}; + +struct OrbisSaveDataIcon { + void* buf; + size_t bufSize; + size_t dataSize; + u8 reserved[32]; +}; + +typedef u32 OrbisSaveDataSaveDataMemoryOption; +#define ORBIS_SAVE_DATA_MEMORY_OPTION_NONE (0x00000000) +#define ORBIS_SAVE_DATA_MEMORY_OPTION_SET_PARAM (0x00000001 << 0) +#define ORBIS_SAVE_DATA_MEMORY_OPTION_DOUBLE_BUFFER (0x00000001 << 1) + +struct OrbisSaveDataMemorySetup2 { + OrbisSaveDataSaveDataMemoryOption option; + s32 userId; + size_t memorySize; + size_t iconMemorySize; + const OrbisSaveDataParam* initParam; + const OrbisSaveDataIcon* initIcon; + u32 slotId; + u8 reserved[20]; +}; + +struct OrbisSaveDataMemorySetupResult { + size_t existedMemorySize; + u8 reserved[16]; +}; + +typedef u32 OrbisSaveDataEventType; +#define SCE_SAVE_DATA_EVENT_TYPE_INVALID (0) +#define SCE_SAVE_DATA_EVENT_TYPE_UMOUNT_BACKUP_END (1) +#define SCE_SAVE_DATA_EVENT_TYPE_BACKUP_END (2) +#define SCE_SAVE_DATA_EVENT_TYPE_SAVE_DATA_MEMORY_SYNC_END (3) + +struct OrbisSaveDataEvent { + OrbisSaveDataEventType type; + s32 errorCode; + s32 userId; + u8 padding[4]; + OrbisSaveDataTitleId titleId; + OrbisSaveDataDirName dirName; + u8 reserved[40]; +}; + +struct OrbisSaveDataMemoryData { + void* buf; + size_t bufSize; + off_t offset; + u8 reserved[40]; +}; + +struct OrbisSaveDataMemoryGet2 { + s32 userId; + u8 padding[4]; + OrbisSaveDataMemoryData* data; + OrbisSaveDataParam* param; + OrbisSaveDataIcon* icon; + u32 slotId; + u8 reserved[28]; +}; + +struct OrbisSaveDataMemorySet2 { + s32 userId; + u8 padding[4]; + const OrbisSaveDataMemoryData* data; + const OrbisSaveDataParam* param; + const OrbisSaveDataIcon* icon; + u32 dataNum; + u8 slotId; + u8 reserved[24]; +}; + +struct OrbisSaveDataCheckBackupData { + s32 userId; + int : 32; + const OrbisSaveDataTitleId* titleId; + const OrbisSaveDataDirName* dirName; + OrbisSaveDataParam* param; + OrbisSaveDataIcon* icon; + u8 reserved[32]; +}; + +struct OrbisSaveDataMountInfo { + u64 blocks; + u64 freeBlocks; + u8 reserved[32]; +}; + +#define ORBIS_SAVE_DATA_BLOCK_SIZE (32768) +#define ORBIS_SAVE_DATA_BLOCKS_MIN2 (96) +#define ORBIS_SAVE_DATA_BLOCKS_MAX (32768) // savedataMount2 mountModes (ORed values) constexpr int ORBIS_SAVE_DATA_MOUNT_MODE_RDONLY = 1; @@ -73,6 +179,69 @@ constexpr int ORBIS_SAVE_DATA_MOUNT_MODE_CREATE = 4; constexpr int ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF = 8; constexpr int ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON = 16; constexpr int ORBIS_SAVE_DATA_MOUNT_MODE_CREATE2 = 32; +typedef struct _OrbisSaveDataEventParam OrbisSaveDataEventParam; + +typedef u32 OrbisSaveDataSortKey; +#define ORBIS_SAVE_DATA_SORT_KEY_DIRNAME (0) +#define ORBIS_SAVE_DATA_SORT_KEY_USER_PARAM (1) +#define ORBIS_SAVE_DATA_SORT_KEY_BLOCKS (2) +#define ORBIS_SAVE_DATA_SORT_KEY_MTIME (3) +#define ORBIS_SAVE_DATA_SORT_KEY_FREE_BLOCKS (5) + +typedef u32 OrbisSaveDataSortOrder; +#define ORBIS_SAVE_DATA_SORT_ORDER_ASCENT (0) +#define ORBIS_SAVE_DATA_SORT_ORDER_DESCENT (1) + +struct OrbisSaveDataDirNameSearchCond { + s32 userId; + int : 32; + const OrbisSaveDataTitleId* titleId; + const OrbisSaveDataDirName* dirName; + OrbisSaveDataSortKey key; + OrbisSaveDataSortOrder order; + u8 reserved[32]; +}; + +struct OrbisSaveDataSearchInfo { + u64 blocks; + u64 freeBlocks; + u8 reserved[32]; +}; + +struct OrbisSaveDataDirNameSearchResult { + u32 hitNum; + int : 32; + OrbisSaveDataDirName* dirNames; + u32 dirNamesNum; + u32 setNum; + OrbisSaveDataParam* params; + OrbisSaveDataSearchInfo* infos; + u8 reserved[12]; + int : 32; +}; + +struct OrbisSaveDataDelete { + s32 userId; + int : 32; + const OrbisSaveDataTitleId* titleId; + const OrbisSaveDataDirName* dirName; + u32 unused; + u8 reserved[32]; + int : 32; +}; + +typedef u32 OrbisSaveDataMemorySyncOption; + +#define SCE_SAVE_DATA_MEMORY_SYNC_OPTION_NONE (0x00000000) +#define SCE_SAVE_DATA_MEMORY_SYNC_OPTION_BLOCKING (0x00000001 << 0) + +struct OrbisSaveDataMemorySync { + s32 userId; + u32 slotId; + OrbisSaveDataMemorySyncOption option; + u8 reserved[28]; + +}; int PS4_SYSV_ABI sceSaveDataAbort(); int PS4_SYSV_ABI sceSaveDataBackup(); @@ -80,7 +249,7 @@ int PS4_SYSV_ABI sceSaveDataBindPsnAccount(); int PS4_SYSV_ABI sceSaveDataBindPsnAccountForSystemBackup(); int PS4_SYSV_ABI sceSaveDataChangeDatabase(); int PS4_SYSV_ABI sceSaveDataChangeInternal(); -int PS4_SYSV_ABI sceSaveDataCheckBackupData(); +int PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData* check); int PS4_SYSV_ABI sceSaveDataCheckBackupDataForCdlg(); int PS4_SYSV_ABI sceSaveDataCheckBackupDataInternal(); int PS4_SYSV_ABI sceSaveDataCheckCloudData(); @@ -98,12 +267,13 @@ int PS4_SYSV_ABI sceSaveDataDebugCreateSaveDataRoot(); int PS4_SYSV_ABI sceSaveDataDebugGetThreadId(); int PS4_SYSV_ABI sceSaveDataDebugRemoveSaveDataRoot(); int PS4_SYSV_ABI sceSaveDataDebugTarget(); -int PS4_SYSV_ABI sceSaveDataDelete(); +int PS4_SYSV_ABI sceSaveDataDelete(const OrbisSaveDataDelete* del); int PS4_SYSV_ABI sceSaveDataDelete5(); int PS4_SYSV_ABI sceSaveDataDeleteAllUser(); int PS4_SYSV_ABI sceSaveDataDeleteCloudData(); int PS4_SYSV_ABI sceSaveDataDeleteUser(); -int PS4_SYSV_ABI sceSaveDataDirNameSearch(); +int PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond* cond, + OrbisSaveDataDirNameSearchResult* result); int PS4_SYSV_ABI sceSaveDataDirNameSearchInternal(); int PS4_SYSV_ABI sceSaveDataDownload(); int PS4_SYSV_ABI sceSaveDataGetAllSize(); @@ -116,15 +286,18 @@ int PS4_SYSV_ABI sceSaveDataGetClientThreadPriority(); int PS4_SYSV_ABI sceSaveDataGetCloudQuotaInfo(); int PS4_SYSV_ABI sceSaveDataGetDataBaseFilePath(); int PS4_SYSV_ABI sceSaveDataGetEventInfo(); -int PS4_SYSV_ABI sceSaveDataGetEventResult(); +int PS4_SYSV_ABI sceSaveDataGetEventResult(const OrbisSaveDataEventParam* eventParam, + OrbisSaveDataEvent* event); int PS4_SYSV_ABI sceSaveDataGetFormat(); int PS4_SYSV_ABI sceSaveDataGetMountedSaveDataCount(); -int PS4_SYSV_ABI sceSaveDataGetMountInfo(); +int PS4_SYSV_ABI sceSaveDataGetMountInfo(const OrbisSaveDataMountPoint* mountPoint, + OrbisSaveDataMountInfo* info); int PS4_SYSV_ABI sceSaveDataGetParam(); int PS4_SYSV_ABI sceSaveDataGetProgress(); int PS4_SYSV_ABI sceSaveDataGetSaveDataCount(); -int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(); -int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(); +int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const u32 userId, void* buf, const size_t bufSize, + const int64_t offset); +int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam); int PS4_SYSV_ABI sceSaveDataGetSaveDataRootDir(); int PS4_SYSV_ABI sceSaveDataGetSaveDataRootPath(); int PS4_SYSV_ABI sceSaveDataGetSaveDataRootUsbPath(); @@ -136,7 +309,8 @@ int PS4_SYSV_ABI sceSaveDataInitialize3(); int PS4_SYSV_ABI sceSaveDataInitializeForCdlg(); int PS4_SYSV_ABI sceSaveDataIsDeletingUsbDb(); int PS4_SYSV_ABI sceSaveDataIsMounted(); -int PS4_SYSV_ABI sceSaveDataLoadIcon(); +int PS4_SYSV_ABI sceSaveDataLoadIcon(const OrbisSaveDataMountPoint* mountPoint, + OrbisSaveDataIcon* icon); int PS4_SYSV_ABI sceSaveDataMount(const OrbisSaveDataMount* mount, OrbisSaveDataMountResult* mount_result); s32 PS4_SYSV_ABI sceSaveDataMount2(const OrbisSaveDataMount2* mount, @@ -150,24 +324,30 @@ int PS4_SYSV_ABI sceSaveDataRegisterEventCallback(); int PS4_SYSV_ABI sceSaveDataRestoreBackupData(); int PS4_SYSV_ABI sceSaveDataRestoreBackupDataForCdlg(); int PS4_SYSV_ABI sceSaveDataRestoreLoadSaveDataMemory(); -int PS4_SYSV_ABI sceSaveDataSaveIcon(); +int PS4_SYSV_ABI sceSaveDataSaveIcon(const OrbisSaveDataMountPoint* mountPoint, + const OrbisSaveDataIcon* icon); int PS4_SYSV_ABI sceSaveDataSetAutoUploadSetting(); int PS4_SYSV_ABI sceSaveDataSetEventInfo(); -int PS4_SYSV_ABI sceSaveDataSetParam(); +int PS4_SYSV_ABI sceSaveDataSetParam(const OrbisSaveDataMountPoint* mountPoint, + OrbisSaveDataParamType paramType, const void* paramBuf, + size_t paramBufSize); int PS4_SYSV_ABI sceSaveDataSetSaveDataLibraryUser(); -int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(); -int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(); -int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(); -int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(); +int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(const u32 userId, const void* buf, + const size_t bufSize, const int64_t offset); +int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam); +int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(u32 userId, size_t memorySize, + OrbisSaveDataParam* param); +int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2* setupParam, + OrbisSaveDataMemorySetupResult* result); int PS4_SYSV_ABI sceSaveDataShutdownStart(); int PS4_SYSV_ABI sceSaveDataSupportedFakeBrokenStatus(); int PS4_SYSV_ABI sceSaveDataSyncCloudList(); -int PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(); +int PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncParam); int PS4_SYSV_ABI sceSaveDataTerminate(); int PS4_SYSV_ABI sceSaveDataTransferringMount(); int PS4_SYSV_ABI sceSaveDataUmount(const OrbisSaveDataMountPoint* mountPoint); int PS4_SYSV_ABI sceSaveDataUmountSys(); -int PS4_SYSV_ABI sceSaveDataUmountWithBackup(); +int PS4_SYSV_ABI sceSaveDataUmountWithBackup(const OrbisSaveDataMountPoint* mountPoint); int PS4_SYSV_ABI sceSaveDataUnregisterEventCallback(); int PS4_SYSV_ABI sceSaveDataUpload(); int PS4_SYSV_ABI Func_02E4C4D201716422(); diff --git a/src/emulator.cpp b/src/emulator.cpp index c16e5b3f..596c526b 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -85,6 +85,9 @@ void Emulator::Run(const std::filesystem::path& file) { } mnt->Mount(mount_data_dir, "/data"); // should just exist, manually create with game serial const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id; + if (!std::filesystem::exists(mount_temp_dir)) { + std::filesystem::create_directory(mount_temp_dir); + } mnt->Mount(mount_temp_dir, "/temp0"); // called in app_content ==> stat/mkdir // Initialize kernel and library facilities.