diff --git a/bin/dev_hdd1/cache/README.txt b/bin/dev_hdd1/cache/README.txt index 9932cff1d7..866145c799 100644 --- a/bin/dev_hdd1/cache/README.txt +++ b/bin/dev_hdd1/cache/README.txt @@ -1 +1 @@ -every Folder in this directory gets cleared when cellSysCacheClear() is called, so don't store important data here \ No newline at end of file +This directory is used for cache functionality, so don't store any data here. diff --git a/bin/dev_hdd1/game/README.txt b/bin/dev_hdd1/game/README.txt new file mode 100644 index 0000000000..fdf4ca2135 --- /dev/null +++ b/bin/dev_hdd1/game/README.txt @@ -0,0 +1 @@ +This directory is used for temporary gamedata functionality, so don't store any data here. diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 0d614cba77..0ff98956e0 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -269,6 +269,21 @@ namespace fxm return nullptr; } + // add fixed object of specified type, replacing previous one if it exists + template std::enable_if_t::value, std::shared_ptr> make_always(Args&&... args) + { + extern std::mutex g_fx_mutex; + extern std::unordered_map> g_fx_map; + + std::lock_guard lock(g_fx_mutex); + + auto ptr = std::make_shared(std::forward(args)...); + + g_fx_map[typeid(T)] = ptr; + + return ptr; + } + // check whether the object exists template bool check() { @@ -315,4 +330,24 @@ namespace fxm return g_fx_map.erase(found), true; } + + // remove fixed object created with type T and return it + template std::shared_ptr withdraw() + { + extern std::mutex g_fx_mutex; + extern std::unordered_map> g_fx_map; + + std::lock_guard lock(g_fx_mutex); + + const auto found = g_fx_map.find(typeid(T)); + + if (found == g_fx_map.end()) + { + return nullptr; + } + + auto ptr = std::static_pointer_cast(std::move(found->second)); + + return g_fx_map.erase(found), ptr; + } } diff --git a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp b/rpcs3/Emu/SysCalls/Modules/cellGame.cpp index bc61b88bd6..9c4fd5be19 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGame.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" +#include "Emu/IdManager.h" #include "Emu/SysCalls/Modules.h" #include "Utilities/rMsgBox.h" @@ -12,9 +13,45 @@ extern Module cellGame; -std::string contentInfo; -std::string usrdir; -bool path_set = false; +// Specified as second content_permission_t constructor argument to inform temporary directory +static struct temporary_content_dir_tag_t{} const temporary_content_dir_tag{}; + +// Normal content directory (if is_temporary is not involved): +// contentInfo = dir +// usrdir = dir + "/USRDIR" +// Temporary content directory: +// contentInfo = "/dev_hdd1/game/" + dir +// usrdir = "/dev_hdd1/game/" + dir + "/USRDIR" +// Usual (persistent) content directory (if is_temporary): +// contentInfo = "/dev_hdd0/game/" + dir +// usrdir = "/dev_hdd0/game/" + dir + "/USRDIR" +struct content_permission_t final +{ + // content directory name or path + const std::string dir; + + // true if temporary directory is created and must be moved or deleted + bool is_temporary = false; + + content_permission_t(const std::string& dir) + : dir(dir) + { + } + + content_permission_t(const std::string& dir, const temporary_content_dir_tag_t&) + : dir(dir) + , is_temporary(true) + { + } + + ~content_permission_t() + { + if (is_temporary) + { + // TODO: delete temporary directory and all its contents + } + } +}; s32 cellHddGameCheck(PPUThread& CPU, u32 version, vm::cptr dirName, u32 errDialog, vm::ptr funcStat, u32 container) { @@ -155,19 +192,23 @@ s32 cellGameBootCheck(vm::ptr type, vm::ptr attributes, vm::ptr("/dev_bdvd/PS3_GAME")) + { + return CELL_GAME_ERROR_BUSY; + } } else if (category.substr(0, 2) == "HG") { std::string titleId = psf.GetString("TITLE_ID"); *type = CELL_GAME_GAMETYPE_HDD; *attributes = 0; // TODO - if (dirName) strcpy_trunc(*dirName, titleId); - contentInfo = "/dev_hdd0/game/" + titleId; - usrdir = "/dev_hdd0/game/" + titleId + "/USRDIR"; - path_set = true; + if (dirName) strcpy_trunc(*dirName, titleId); + + if (!fxm::make("/dev_hdd0/game/" + titleId)) + { + return CELL_GAME_ERROR_BUSY; + } } else if (category.substr(0, 2) == "GD") { @@ -175,9 +216,11 @@ s32 cellGameBootCheck(vm::ptr type, vm::ptr attributes, vm::ptr("/dev_bdvd/PS3_GAME")) + { + return CELL_GAME_ERROR_BUSY; + } } else if (psf) { @@ -216,12 +259,12 @@ s32 cellGamePatchCheck(vm::ptr size, vm::ptr reserved return CELL_GAME_ERROR_NOTPATCH; } - std::string titleId = psf.GetString("TITLE_ID"); - contentInfo = "/dev_hdd0/game/" + titleId; - usrdir = "/dev_hdd0/game/" + titleId + "/USRDIR"; - path_set = true; + if (!fxm::make("/dev_hdd0/game/" + psf.GetString("TITLE_ID"))) + { + return CELL_GAME_ERROR_BUSY; + } - return CELL_GAME_RET_OK; + return CELL_OK; } s32 cellGameDataCheck(u32 type, vm::cptr dirName, vm::ptr size) @@ -251,15 +294,13 @@ s32 cellGameDataCheck(u32 type, vm::cptr dirName, vm::ptr("/dev_bdvd/PS3_GAME")) + { + return CELL_GAME_ERROR_BUSY; + } } else { @@ -268,15 +309,13 @@ s32 cellGameDataCheck(u32 type, vm::cptr dirName, vm::ptr(dir)) + { + return CELL_GAME_ERROR_BUSY; + } } return CELL_GAME_RET_OK; @@ -291,32 +330,40 @@ s32 cellGameContentPermit(vm::ptr contentInfoPath, vm: return CELL_GAME_ERROR_PARAM; } - cellGame.Warning("cellGameContentPermit(): path_set=%d, contentInfo='%s', usrdir='%s'", path_set, contentInfo, usrdir); + const auto path_set = fxm::withdraw(); if (!path_set) { return CELL_GAME_ERROR_FAILURE; } - if (contentInfo.size() == 9 && usrdir.empty()) + if (path_set->is_temporary) { - if (Emu.GetVFS().RenameDir("/dev_hdd0/game/TMP_" + contentInfo, "/dev_hdd0/game/" + contentInfo)) + const std::string dir = "/dev_hdd0/game/" + path_set->dir; + + // make temporary directory persistent + if (Emu.GetVFS().RenameDir("/dev_hdd1/game/" + path_set->dir, dir)) { - cellGame.Success("cellGameContentPermit(): gamedata directory created ('/dev_hdd0/game/%s')", contentInfo); + cellGame.Success("cellGameContentPermit(): '%s' directory created", dir); + } + else + { + throw EXCEPTION("Cannot create gamedata directory"); } - contentInfo = "/dev_hdd0/game/" + contentInfo; - usrdir = contentInfo + "/USRDIR"; + // prevent deleting directory + path_set->is_temporary = false; + + strcpy_trunc(*contentInfoPath, dir); + strcpy_trunc(*usrdirPath, dir + "/USRDIR"); + } + else + { + strcpy_trunc(*contentInfoPath, path_set->dir); + strcpy_trunc(*usrdirPath, path_set->dir + "/USRDIR"); } - - strcpy_trunc(*contentInfoPath, contentInfo); - strcpy_trunc(*usrdirPath, usrdir); - - contentInfo = ""; - usrdir = ""; - path_set = false; - return CELL_GAME_RET_OK; + return CELL_OK; } s32 cellGameDataCheckCreate2(PPUThread& CPU, u32 version, vm::cptr dirName, u32 errDialog, vm::ptr funcStat, u32 container) @@ -429,8 +476,8 @@ s32 cellGameCreateGameData(vm::ptr init, vm::ptrtitleId; - std::string tmp_contentInfo = "/dev_hdd0/game/TMP_" + dir; - std::string tmp_usrdir = "/dev_hdd0/game/TMP_" + dir + "/USRDIR"; + std::string tmp_contentInfo = "/dev_hdd1/game/" + dir; + std::string tmp_usrdir = "/dev_hdd1/game/" + dir + "/USRDIR"; if (!Emu.GetVFS().CreateDir(tmp_contentInfo)) { @@ -444,14 +491,15 @@ s32 cellGameCreateGameData(vm::ptr init, vm::ptr(dir, temporary_content_dir_tag)) + { + return CELL_GAME_ERROR_BUSY; + } + // cellGameContentPermit should then move files in non-temporary location and return their non-temporary displacement strcpy_trunc(*tmp_contentInfoPath, tmp_contentInfo); strcpy_trunc(*tmp_usrdirPath, tmp_usrdir); - contentInfo = dir; - usrdir.clear(); - path_set = true; - cellGame.Success("cellGameCreateGameData(): temporary gamedata directory created ('%s')", tmp_contentInfo); // TODO: set initial PARAM.SFO parameters @@ -665,10 +713,6 @@ void cellSysutil_GameData_init() Module cellGame("cellGame", []() { - contentInfo = ""; - usrdir = ""; - path_set = false; - REG_FUNC(cellGame, cellGameBootCheck); REG_FUNC(cellGame, cellGamePatchCheck); REG_FUNC(cellGame, cellGameDataCheck);