mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-06 00:59:18 +00:00
cellSysCacheClear/Mount() improved
Clear() error checking simplified a bit Mount() now clears cache if ID was changed from last or NULL specified. Implemented vfs::host::remove_all(): Clear() now uses vfs::host::remove_all() to match behaviour on Windows with ps3
This commit is contained in:
parent
83f253636a
commit
65e47490c4
@ -72,8 +72,18 @@ extern void sysutil_send_system_cmd(u64 status, u64 param)
|
||||
|
||||
struct syscache
|
||||
{
|
||||
atomic_t<u32> state = 0;
|
||||
std::string cache_path;
|
||||
atomic_t<bool> mounted = false;
|
||||
std::string cache_id;
|
||||
shared_mutex mtx;
|
||||
|
||||
~syscache()
|
||||
{
|
||||
// Check if mounted and cache_id is different than already written empty value
|
||||
if (!cache_id.empty())
|
||||
{
|
||||
fs::write_file(fs::get_cache_dir() + "/cache/cacheId", fs::rewrite, cache_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -309,22 +319,22 @@ s32 cellSysutilUnregisterCallback(u32 slot)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
const std::string cache_path = "/dev_hdd1/cache";
|
||||
|
||||
s32 cellSysCacheClear()
|
||||
{
|
||||
cellSysutil.warning("cellSysCacheClear()");
|
||||
|
||||
const auto cache = g_fxo->get<syscache>();
|
||||
|
||||
if (!cache->state)
|
||||
if (!cache->mounted)
|
||||
{
|
||||
return CELL_SYSCACHE_ERROR_NOTMOUNTED;
|
||||
}
|
||||
|
||||
std::string local_dir = vfs::get(cache->cache_path);
|
||||
|
||||
if (!fs::remove_all(local_dir, false))
|
||||
if (!vfs::host::remove_all(vfs::get(cache_path), Emu.GetHdd1Dir(), false))
|
||||
{
|
||||
cellSysutil.error("cellSysCacheClear(): failed to clear directory '%s' (%s)", cache->cache_path, fs::g_tls_error);
|
||||
cellSysutil.error("cellSysCacheClear(): failed to clear directory '%s' (%s)", cache_path, fs::g_tls_error);
|
||||
return CELL_SYSCACHE_ERROR_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
@ -343,16 +353,52 @@ s32 cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
|
||||
}
|
||||
|
||||
std::string cache_id = param->cacheId;
|
||||
std::string cache_path = "/dev_hdd1/cache/" + cache_id;
|
||||
strcpy_trunc(param->getCachePath, cache_path);
|
||||
|
||||
if (!fs::create_dir(vfs::get(cache_path)) && !cache_id.empty())
|
||||
cellSysutil.notice("cellSysCacheMount: cache id=%s", cache_id);
|
||||
|
||||
std::lock_guard lock(cache->mtx);
|
||||
|
||||
if (!cache->mounted.exchange(true))
|
||||
{
|
||||
return CELL_SYSCACHE_RET_OK_RELAYED;
|
||||
// Get last cache ID, lasts between application boots
|
||||
fs::file last_id(fs::get_cache_dir() + "/cache/cacheId", fs::read + fs::write + fs::create);
|
||||
const auto id_size = last_id.size();
|
||||
|
||||
// Compare specified ID with old one (if size is 0 clear unconditionally)
|
||||
const bool relayed = id_size && id_size == cache_id.size() && [&]()
|
||||
{
|
||||
char buf[CELL_SYSCACHE_ID_SIZE - 1];
|
||||
last_id.read(buf, id_size);
|
||||
return memcmp(buf, cache_id.c_str(), id_size) == 0;
|
||||
}();
|
||||
|
||||
// Protection against rpcs3 crash (syscache dtor wasn't called)
|
||||
// Clear cacheId (clear cache on next startup)
|
||||
last_id.trunc(0);
|
||||
|
||||
if (relayed)
|
||||
{
|
||||
cache->cache_id = std::move(cache_id);
|
||||
return CELL_SYSCACHE_RET_OK_RELAYED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If null term specified at start it must be cleared uncondionally
|
||||
if (!cache_id.empty() && cache->cache_id == cache_id)
|
||||
{
|
||||
return CELL_SYSCACHE_RET_OK_RELAYED;
|
||||
}
|
||||
}
|
||||
|
||||
cache->cache_path = std::move(cache_path);
|
||||
cache->state = 1;
|
||||
// Set new cache ID (clear previous)
|
||||
if (!vfs::host::remove_all(vfs::get(cache_path), Emu.GetHdd1Dir(), false))
|
||||
{
|
||||
cellSysutil.error("cellSysCacheMount(): failed to clear directory '%s' (%s)", cache_path, fs::g_tls_error);
|
||||
}
|
||||
|
||||
cache->cache_id = std::move(cache_id);
|
||||
return CELL_SYSCACHE_RET_OK_CLEARED;
|
||||
}
|
||||
|
||||
|
@ -595,3 +595,56 @@ bool vfs::host::unlink(const std::string& path, const std::string& dev_root)
|
||||
|
||||
return fs::remove_file(path);
|
||||
}
|
||||
|
||||
bool vfs::host::remove_all(const std::string& path, const std::string& dev_root, bool remove_root)
|
||||
{
|
||||
if (remove_root)
|
||||
{
|
||||
// Rename to special dummy folder which will be ignored by VFS (but opened file handles can still read or write it)
|
||||
const std::string dummy = fmt::format(u8"%s/$%s%s", dev_root, fmt::base57(std::hash<std::string>()(path)), fmt::base57(__rdtsc()));
|
||||
|
||||
if (!vfs::host::rename(path, dummy, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fs::remove_all(dummy))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto root_dir = fs::dir(path);
|
||||
|
||||
if (!root_dir)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& entry : root_dir)
|
||||
{
|
||||
if (entry.name == "." || entry.name == "..")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!entry.is_directory)
|
||||
{
|
||||
if (!vfs::host::unlink(path + '/' + entry.name, dev_root))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vfs::host::remove_all(path + '/' + entry.name, dev_root))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -26,5 +26,8 @@ namespace vfs
|
||||
|
||||
// Delete file without deleting its contents, emulated with MoveFileEx on Windows
|
||||
bool unlink(const std::string& path, const std::string& dev_root);
|
||||
|
||||
// Delete folder contents using rename, done atomically if remove_root is true
|
||||
bool remove_all(const std::string& path, const std::string& dev_root, bool remove_root = true);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user