From 6610abcd5f24da758f500b7f414309454bc4065e Mon Sep 17 00:00:00 2001 From: Dangles Date: Mon, 17 Jul 2017 02:10:45 +1000 Subject: [PATCH] Minor changes for save data utility (#3005) --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 149 +++++++++++++++++------- rpcs3/Emu/Cell/Modules/cellSaveData.h | 2 +- rpcs3/Emu/Cell/Modules/cellSysutil.h | 2 +- 3 files changed, 107 insertions(+), 46 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 4d2f57948a..a94a1efd5f 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Emu/System.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/Modules/cellSysutil.h" #include "cellSaveData.h" @@ -63,7 +64,6 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, PFuncFile funcFile, u32 container, u32 unknown, vm::ptr userdata, u32 userId, PFuncDone funcDone) { // TODO: check arguments - std::unique_lock lock(g_savedata_mutex, std::try_to_lock); if (!lock) @@ -82,6 +82,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, vm::ptr fileGet = g_savedata_context.ptr(&savedata_context::fileGet); vm::ptr fileSet = g_savedata_context.ptr(&savedata_context::fileSet); + //TODO: get current user ID + // userId(0) = CELL_SYSUTIL_USERID_CURRENT // path of the specified user (00000001 by default) const std::string& base_dir = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u)); @@ -100,6 +102,7 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, const auto prefix_list = fmt::split(setList->dirNamePrefix.get_ptr(), { "|" }); + // get the saves matching the supplied prefix for (const auto& entry : fs::dir(base_dir)) { if (!entry.is_directory) @@ -211,13 +214,15 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, if (result->result < 0) { + //TODO: display dialog cellSaveData.warning("savedata_op(): funcList returned < 0."); return CELL_SAVEDATA_ERROR_CBRESULT; } // if the callback has returned ok, lets return OK. // typically used at game launch when no list is actually required. - if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)) + // CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM is only valid for funcFile and funcDone + if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) { return CELL_OK; } @@ -236,6 +241,16 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, return true; }), save_entries.end()); + // Add any new data (not currently supported by the UI) + //if (listSet->newData) + //{ + // SaveDataEntry *_saveDataEntry = new SaveDataEntry(); + // _saveDataEntry->dirName = listSet->newData->dirName.get_ptr(); + + // save_entry.dirName = listSet->newData->dirName.get_ptr(); + // save_entries.emplace_back(*_saveDataEntry); + //} + // Focus save data s32 focused = -1; @@ -296,6 +311,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } case CELL_SAVEDATA_FOCUSPOS_NEWDATA: { + //TODO: If adding the new data to the save_entries vector + // to be displayed in the save mangaer UI, it should be focused here break; } default: @@ -339,8 +356,19 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, // Fixed Callback funcFixed(ppu, result, listGet, fixedSet); + // skip all following steps if OK_LAST + if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) + { + return CELL_OK; + } + if (result->result < 0) { + //TODO: Show msgDialog if required + // depends on fixedSet->option + // 0 = none + // 1 = skip confirmation dialog + cellSaveData.warning("savedata_op(): funcFixed returned < 0."); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -363,10 +391,7 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, { save_entry.dirName = fixedSet->dirName.get_ptr(); } - if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)) - { - return CELL_OK; - } + } if (selected >= 0) @@ -479,6 +504,11 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, return CELL_SAVEDATA_ERROR_CBRESULT; } + if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) + { + return CELL_OK; + } + if (statSet->setParam) { // Update PARAM.SFO @@ -498,18 +528,20 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, { "TITLE", psf::string(128, statSet->setParam->title) }, }); } - else if (psf.empty()) - { - // setParam is NULL for new savedata: abort operation - - return CELL_OK; - } + //else if (psf.empty()) + //{ + // // setParam is specified if something required updating. + // // Do not exit. Recreate mode will handle the rest + // //return CELL_OK; + //} switch (const u32 mode = statSet->reCreateMode & 0xffff) { case CELL_SAVEDATA_RECREATE_NO: { - cellSaveData.error("Savedata %s considered broken", save_entry.dirName); + //CELL_SAVEDATA_RECREATE_NO = overwrite and let the user know, not data is corrupt. + //cellSaveData.error("Savedata %s considered broken", save_entry.dirName); + //TODO: if this is a save, and it's not auto, then show a dialog // fallthrough } @@ -521,7 +553,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, case CELL_SAVEDATA_RECREATE_YES: case CELL_SAVEDATA_RECREATE_YES_RESET_OWNER: { - // TODO? + + // TODO: Only delete data, not owner info for (const auto& entry : fs::dir(dir_path)) { if (!entry.is_directory) @@ -530,12 +563,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } } + //TODO: probably not deleting owner info if (!statSet->setParam) { // Savedata deleted and setParam is NULL: delete directory and abort operation if (fs::remove_dir(dir_path)) cellSaveData.error("savedata_op(): savedata directory %s deleted", save_entry.dirName); - return CELL_OK; + //return CELL_OK; } break; @@ -549,16 +583,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } } - if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)) - { - return CELL_OK; - } + // Create save directory if necessary if (psf.size() && save_entry.isNew && !fs::create_dir(dir_path)) - { - // Let's ignore this error for now + { cellSaveData.warning("savedata_op(): failed to create %s", dir_path); + return CELL_SAVEDATA_ERROR_ACCESS_ERROR; } // Enter the loop where the save files are read/created/deleted @@ -578,9 +609,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM) { + //todo: display user prompt break; } + //TODO: Show progress + // if it's not an auto load/save + std::string file_path; switch (const u32 type = fileSet->fileType) @@ -681,6 +716,51 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, return CELL_OK; } +s32 static NEVER_INLINE save_op_get_list_item(vm::cptr dirName, vm::ptr dir, vm::ptr sysFileParam, vm::ptr bind, vm::ptr sizeKB, u32 userId) +{ + + //TODO: accurately get the current user + if (userId == 0) + { + userId = 1u; + } + std::string save_path = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/%s/", userId, dirName.get_ptr())); + std::string sfo = save_path + "param.sfo"; + + if (!fs::is_dir(save_path) && !fs::is_file(sfo)) + { + cellSaveData.error("cellSaveDataGetListItem(): Savedata at %s does not exist", dirName); + return CELL_SAVEDATA_ERROR_NODATA; + } + + auto psf = psf::load_object(fs::file(sfo)); + + if (sysFileParam) + { + strcpy_trunc(sysFileParam->listParam, psf.at("SAVEDATA_LIST_PARAM").as_string()); + strcpy_trunc(sysFileParam->title, psf.at("TITLE").as_string()); + strcpy_trunc(sysFileParam->subTitle, psf.at("SUB_TITLE").as_string()); + strcpy_trunc(sysFileParam->detail, psf.at("DETAIL").as_string()); + } + + fs::stat_t dir_info{}; + if (!fs::stat(save_path, dir_info)) + { + return CELL_SAVEDATA_ERROR_INTERNAL; + } + + // get file stats, namely directory + strcpy_trunc(dir->dirName, dirName.get_ptr()); + dir->atime = dir_info.atime; + dir->ctime = dir_info.ctime; + dir->mtime = dir_info.mtime; + + //TODO: Set bind in accordance to any problems + *bind = 0; + + return CELL_OK; +} + // Functions s32 cellSaveDataListSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) @@ -949,27 +1029,8 @@ s32 cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr dirName, u32 maxSize s32 cellSaveDataGetListItem(vm::cptr dirName, vm::ptr dir, vm::ptr sysFileParam, vm::ptr bind, vm::ptr sizeKB) { cellSaveData.warning("cellSavaDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x)", dirName, dir, sysFileParam, bind, sizeKB); - - std::string save_path = vfs::get(fmt::format("/dev_hdd0/home/00000001/savedata/%s/", dirName.get_ptr())); - std::string sfo = save_path + "param.sfo"; - - if (!fs::is_dir(save_path) && !fs::is_file(sfo)) - { - cellSaveData.error("cellSaveDataGetListItem(): Savedata at %s does not exist", dirName); - return CELL_SAVEDATA_ERROR_NODATA; - } - - auto psf = psf::load_object(fs::file(sfo)); - - if (sysFileParam) - { - strcpy_trunc(sysFileParam->listParam, psf.at("SAVEDATA_LIST_PARAM").as_string()); - strcpy_trunc(sysFileParam->title, psf.at("TITLE").as_string()); - strcpy_trunc(sysFileParam->subTitle, psf.at("SUB_TITLE").as_string()); - strcpy_trunc(sysFileParam->detail, psf.at("DETAIL").as_string()); - } - - return CELL_OK; + + return save_op_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, 0); } s32 cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr userdata) @@ -1009,9 +1070,9 @@ s32 cellSaveDataUserFixedExport(ppu_thread& ppu, u32 userId, vm::cptr dirN s32 cellSaveDataUserGetListItem(u32 userId, vm::cptr dirName, vm::ptr dir, vm::ptr sysFileParam, vm::ptr bind, vm::ptr sizeKB) { - UNIMPLEMENTED_FUNC(cellSaveData); + cellSaveData.warning("cellSavaDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x, userID=*0x%x)", dirName, dir, sysFileParam, bind, sizeKB, userId); - return CELL_OK; + return save_op_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, userId); } void cellSysutil_SaveData_init() diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h index d10e0d68f9..600b8ae852 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.h +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once namespace vm { using namespace ps3; } diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.h b/rpcs3/Emu/Cell/Modules/cellSysutil.h index c1c60f5b64..037290604c 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.h +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once namespace vm { using namespace ps3; }