fixup hdd1 cache

This commit is contained in:
Eladash 2024-01-15 10:54:11 +02:00 committed by Elad.Ash
parent 9c354ee269
commit e4c9af176b
3 changed files with 71 additions and 18 deletions

View File

@ -51,10 +51,15 @@ struct syscache_info
const auto lock = init.init();
// Extract cache id from path
cache_id = Emu.hdd1;
if (cache_id.back() == '/')
cache_id.resize(cache_id.size() - 1);
cache_id = cache_id.substr(cache_id.find_last_of('/') + 1);
std::string_view id = Emu.hdd1;
id = id.substr(0, id.find_last_not_of(fs::delim) + 1);
id = id.substr(id.find_last_of(fs::delim) + 1);
cache_id = std::string{id};
if (!Emu.DeserialManager() && !fs::write_file<true>(get_syscache_state_corruption_indicator_file_path(Emu.hdd1), fs::write_new))
{
fmt::throw_exception("Failed to create HDD1 corruption indicator file! (path='%s', reason='%s')", Emu.hdd1, fs::g_tls_error);
}
cellSysutil.success("Retained cache from parent process: %s", Emu.hdd1);
return;
@ -67,13 +72,17 @@ struct syscache_info
{
if (entry.is_directory && entry.name.starts_with(prefix))
{
if (fs::is_file(get_syscache_state_corruption_indicator_file_path(cache_root + '/' + entry.name)))
cache_id = vfs::unescape(entry.name);
if (fs::is_file(get_syscache_state_corruption_indicator_file_path(cache_root + '/' + cache_id)))
{
// State is not complete
break;
clear(true);
cache_id.clear();
continue;
}
cache_id = std::move(entry.name);
cellSysutil.notice("Retained cache from past data: %s", cache_root + '/' + cache_id);
break;
}
}
@ -172,13 +181,22 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
auto& cache = g_fxo->get<syscache_info>();
if (!param || (param->cacheId[0] && sysutil_check_name_string(param->cacheId, 1, CELL_SYSCACHE_ID_SIZE) != 0))
if (!param)
{
return CELL_SYSCACHE_ERROR_PARAM;
}
std::string cache_name;
ensure(vm::read_string(param.ptr(&CellSysCacheParam::cacheId).addr(), sizeof(param->cacheId), cache_name), "Access violation");
if (!cache_name.empty() && sysutil_check_name_string(cache_name.data(), 1, CELL_SYSCACHE_ID_SIZE) != 0)
{
return CELL_SYSCACHE_ERROR_PARAM;
}
// Full virtualized cache id (with title id included)
std::string cache_id = vfs::escape(Emu.GetTitleID() + '_' + param->cacheId);
std::string cache_id = vfs::escape(Emu.GetTitleID() + '_' + cache_name);
// Full path to virtual cache root (/dev_hdd1)
std::string new_path = cache.cache_root + cache_id + '/';
@ -194,7 +212,7 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
std::lock_guard lock0(g_mp_sys_dev_hdd1.mutex);
// Check if can reuse existing cache (won't if cache id is an empty string or cache is damaged/incomplete)
if (param->cacheId[0] && cache_id == cache.cache_id && !fs::is_file(get_syscache_state_corruption_indicator_file_path(cache.cache_root + cache_id)))
if (!cache_name.empty() && cache_id == cache.cache_id)
{
// Isn't mounted yet on first call to cellSysCacheMount
if (vfs::mount("/dev_hdd1", new_path))
@ -204,7 +222,7 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
return not_an_error(CELL_SYSCACHE_RET_OK_RELAYED);
}
const bool can_create = cache.cache_id != cache_id;
const bool can_create = cache.cache_id != cache_id || !cache.cache_id.empty();
if (!cache.cache_id.empty())
{
@ -231,6 +249,11 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
}
}
if (!fs::write_file<true>(get_syscache_state_corruption_indicator_file_path(new_path), fs::write_new))
{
fmt::throw_exception("Failed to create HDD1 corruption indicator file! (path='%s', reason='%s')", new_path, fs::g_tls_error);
}
if (vfs::mount("/dev_hdd1", new_path))
g_fxo->get<lv2_fs_mount_info_map>().add("/dev_hdd1", &g_mp_sys_dev_hdd1);

View File

@ -91,6 +91,8 @@ extern void signal_system_cache_can_stay();
fs::file make_file_view(const fs::file& file, u64 offset, u64 size);
extern std::string get_syscache_state_corruption_indicator_file_path(std::string_view dir_path);
fs::file g_tty;
atomic_t<s64> g_tty_size{0};
std::array<std::deque<std::string>, 16> g_tty_input;
@ -1103,7 +1105,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
}
}
auto load_tar = [&](const std::string& path)
auto load_tar = [&](const std::string& path, const std::string& special_file)
{
const usz size = m_ar->pop<usz>();
const usz max_data_size = m_ar->get_size(utils::add_saturate<usz>(size, m_ar->pos));
@ -1115,6 +1117,11 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
fs::remove_all(path, size == 0);
if (!special_file.empty())
{
fs::write_file<true>(special_file, fs::write_new);
}
if (size)
{
m_ar->breathe(true);
@ -1134,7 +1141,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
if (!hdd1.empty())
{
hdd1 = rpcs3::utils::get_hdd1_dir() + "caches/" + hdd1 + "/";
load_tar(hdd1);
load_tar(hdd1, get_syscache_state_corruption_indicator_file_path(hdd1));
}
for (const std::string hdd0_game = rpcs3::utils::get_hdd0_dir() + "game/";;)
@ -1152,7 +1159,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
fmt::throw_exception("HDD0 deserialization failed: Invalid directory name: %s, ar=%s", dirname.substr(0, CELL_GAME_DIRNAME_SIZE + 1), *m_ar);
}
load_tar(hdd0_game + game_data);
load_tar(hdd0_game + game_data, "");
}
// Reserved area

View File

@ -232,6 +232,9 @@ bool tar_object::extract(std::string prefix_path, bool is_vfs)
const TARHeader& header = iter->second.second;
const std::string& name = iter->first;
// Backwards compatibility measure
const bool should_ignore = name.find(reinterpret_cast<const char*>(u8"")) != umax;
std::string result = name;
if (!prefix_path.empty())
@ -291,7 +294,16 @@ bool tar_object::extract(std::string prefix_path, bool is_vfs)
std::unique_ptr<utils::serial> file_data = get_file(name);
fs::file file(result, fs::rewrite);
fs::file file;
if (should_ignore)
{
file = fs::make_stream<std::vector<u8>>();
}
else
{
file.open(result, fs::rewrite);
}
if (file && file_data)
{
@ -301,7 +313,7 @@ bool tar_object::extract(std::string prefix_path, bool is_vfs)
if (unread_size == 0)
{
file.write(filedata_span.data(), filedata_span.size());
file.write(filedata_span.data(), should_ignore ? 0 : filedata_span.size());
continue;
}
@ -310,7 +322,7 @@ bool tar_object::extract(std::string prefix_path, bool is_vfs)
if (usz read_size = filedata_span.size() - unread_size)
{
ensure(file_data->try_read(filedata_span.first(read_size)) == 0);
file.write(filedata_span.data(), read_size);
file.write(filedata_span.data(), should_ignore ? 0 : read_size);
}
break;
@ -318,6 +330,7 @@ bool tar_object::extract(std::string prefix_path, bool is_vfs)
file.close();
file_data->seek_pos(m_ar_tar_start + largest_offset, true);
if (!m_file)
@ -327,6 +340,11 @@ bool tar_object::extract(std::string prefix_path, bool is_vfs)
m_ar->m_max_data = restore_limit;
}
if (should_ignore)
{
break;
}
if (mtime != umax && !fs::utime(result, atime, mtime))
{
tar_log.error("TAR Loader: fs::utime failed on %s (%s)", result, fs::g_tls_error);
@ -351,6 +369,11 @@ bool tar_object::extract(std::string prefix_path, bool is_vfs)
case '5':
{
if (should_ignore)
{
break;
}
if (!fs::create_path(result))
{
tar_log.error("TAR Loader: failed to create directory %s (%s)", name, fs::g_tls_error);
@ -576,7 +599,7 @@ void tar_object::save_directory(const std::string& target_path, utils::serial& a
{
exists = true;
if (entry.name.find_first_not_of('.') == umax)
if (entry.name.find_first_not_of('.') == umax || entry.name.starts_with(reinterpret_cast<const char*>(u8"")))
{
continue;
}