cellSaveData: add auto maintenance routine in Emu.Init()

This routine:
1) Removes junk backup directories
2) Fixes interrupted save data process in edge case
This case can happen if emu terminates between two atomic renames.

Also use directory renaming technique for delete op.
Also rewrite recreate operation to be part of atomic process.
This commit is contained in:
Nekotekina 2019-09-25 01:49:13 +03:00
parent 297016aba3
commit f841b47b6b
2 changed files with 75 additions and 25 deletions

View file

@ -355,6 +355,8 @@ void Emulator::Init()
}
};
const std::string save_path = dev_hdd0 + "home/" + m_usr + "/savedata/";
if (g_cfg.vfs.init_dirs)
{
make_path_verbose(dev_hdd0);
@ -367,7 +369,7 @@ void Emulator::Init()
make_path_verbose(dev_hdd0 + "home/");
make_path_verbose(dev_hdd0 + "home/" + m_usr + "/");
make_path_verbose(dev_hdd0 + "home/" + m_usr + "/exdata/");
make_path_verbose(dev_hdd0 + "home/" + m_usr + "/savedata/");
make_path_verbose(save_path);
make_path_verbose(dev_hdd0 + "home/" + m_usr + "/trophy/");
if (!fs::write_file(dev_hdd0 + "home/" + m_usr + "/localusername", fs::create + fs::excl + fs::write, "User"s))
@ -385,6 +387,40 @@ void Emulator::Init()
make_path_verbose(dev_hdd1 + "game/");
}
// Fixup savedata
for (const auto& entry : fs::dir(save_path))
{
if (entry.is_directory && entry.name.compare(0, 8, ".backup_", 8) == 0)
{
const std::string desired = entry.name.substr(8);
const std::string pending = save_path + ".working_" + desired;
if (fs::is_dir(pending))
{
// Finalize interrupted saving
if (!fs::rename(pending, save_path + desired, false))
{
LOG_FATAL(GENERAL, "Failed to fix save data: %s (%s)", pending, fs::g_tls_error);
continue;
}
else
{
LOG_SUCCESS(GENERAL, "Fixed save data: %s", desired);
}
}
// Remove pending backup data
if (!fs::remove_all(save_path + entry.name))
{
LOG_FATAL(GENERAL, "Failed to remove save data backup: %s%s (%s)", save_path, entry.name, fs::g_tls_error);
}
else
{
LOG_SUCCESS(GENERAL, "Removed save data backup: %s%s", save_path, entry.name);
}
}
}
make_path_verbose(fs::get_cache_dir() + "shaderlog/");
make_path_verbose(fs::get_config_dir() + "captures/");