Minor changes for save data utility (#3005)

This commit is contained in:
Dangles 2017-07-17 02:10:45 +10:00 committed by Ivan
commit 6610abcd5f
3 changed files with 107 additions and 46 deletions

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "cellSaveData.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<void> userdata, u32 userId, PFuncDone funcDone) PFuncFile funcFile, u32 container, u32 unknown, vm::ptr<void> userdata, u32 userId, PFuncDone funcDone)
{ {
// TODO: check arguments // TODO: check arguments
std::unique_lock<std::mutex> lock(g_savedata_mutex, std::try_to_lock); std::unique_lock<std::mutex> lock(g_savedata_mutex, std::try_to_lock);
if (!lock) if (!lock)
@ -82,6 +82,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
vm::ptr<CellSaveDataFileGet> fileGet = g_savedata_context.ptr(&savedata_context::fileGet); vm::ptr<CellSaveDataFileGet> fileGet = g_savedata_context.ptr(&savedata_context::fileGet);
vm::ptr<CellSaveDataFileSet> fileSet = g_savedata_context.ptr(&savedata_context::fileSet); vm::ptr<CellSaveDataFileSet> 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) // 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)); 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(), { "|" }); 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)) for (const auto& entry : fs::dir(base_dir))
{ {
if (!entry.is_directory) 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) if (result->result < 0)
{ {
//TODO: display dialog
cellSaveData.warning("savedata_op(): funcList returned < 0."); cellSaveData.warning("savedata_op(): funcList returned < 0.");
return CELL_SAVEDATA_ERROR_CBRESULT; return CELL_SAVEDATA_ERROR_CBRESULT;
} }
// if the callback has returned ok, lets return OK. // if the callback has returned ok, lets return OK.
// typically used at game launch when no list is actually required. // 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; return CELL_OK;
} }
@ -236,6 +241,16 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
return true; return true;
}), save_entries.end()); }), 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 // Focus save data
s32 focused = -1; 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: 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; break;
} }
default: default:
@ -339,8 +356,19 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
// Fixed Callback // Fixed Callback
funcFixed(ppu, result, listGet, fixedSet); 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) 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."); cellSaveData.warning("savedata_op(): funcFixed returned < 0.");
return CELL_SAVEDATA_ERROR_CBRESULT; 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(); 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) 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; return CELL_SAVEDATA_ERROR_CBRESULT;
} }
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST)
{
return CELL_OK;
}
if (statSet->setParam) if (statSet->setParam)
{ {
// Update PARAM.SFO // 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) }, { "TITLE", psf::string(128, statSet->setParam->title) },
}); });
} }
else if (psf.empty()) //else if (psf.empty())
{ //{
// setParam is NULL for new savedata: abort operation // // setParam is specified if something required updating.
// // Do not exit. Recreate mode will handle the rest
return CELL_OK; // //return CELL_OK;
} //}
switch (const u32 mode = statSet->reCreateMode & 0xffff) switch (const u32 mode = statSet->reCreateMode & 0xffff)
{ {
case CELL_SAVEDATA_RECREATE_NO: 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 // 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:
case CELL_SAVEDATA_RECREATE_YES_RESET_OWNER: case CELL_SAVEDATA_RECREATE_YES_RESET_OWNER:
{ {
// TODO?
// TODO: Only delete data, not owner info
for (const auto& entry : fs::dir(dir_path)) for (const auto& entry : fs::dir(dir_path))
{ {
if (!entry.is_directory) 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) if (!statSet->setParam)
{ {
// Savedata deleted and setParam is NULL: delete directory and abort operation // 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); if (fs::remove_dir(dir_path)) cellSaveData.error("savedata_op(): savedata directory %s deleted", save_entry.dirName);
return CELL_OK; //return CELL_OK;
} }
break; 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 // Create save directory if necessary
if (psf.size() && save_entry.isNew && !fs::create_dir(dir_path)) 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); 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 // 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) if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)
{ {
//todo: display user prompt
break; break;
} }
//TODO: Show progress
// if it's not an auto load/save
std::string file_path; std::string file_path;
switch (const u32 type = fileSet->fileType) 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; return CELL_OK;
} }
s32 static NEVER_INLINE save_op_get_list_item(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> 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 // Functions
s32 cellSaveDataListSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, s32 cellSaveDataListSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata) PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
@ -949,27 +1029,8 @@ s32 cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr<char> dirName, u32 maxSize
s32 cellSaveDataGetListItem(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB) s32 cellSaveDataGetListItem(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB)
{ {
cellSaveData.warning("cellSavaDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x)", dirName, dir, sysFileParam, bind, 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())); return save_op_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, 0);
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;
} }
s32 cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata) s32 cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
@ -1009,9 +1070,9 @@ s32 cellSaveDataUserFixedExport(ppu_thread& ppu, u32 userId, vm::cptr<char> dirN
s32 cellSaveDataUserGetListItem(u32 userId, vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB) s32 cellSaveDataUserGetListItem(u32 userId, vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> 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() void cellSysutil_SaveData_init()

View file

@ -1,4 +1,4 @@
#pragma once #pragma once
namespace vm { using namespace ps3; } namespace vm { using namespace ps3; }

View file

@ -1,4 +1,4 @@
#pragma once #pragma once
namespace vm { using namespace ps3; } namespace vm { using namespace ps3; }