Atomic PARAM.SFO writes

This commit is contained in:
Eladash 2021-02-21 21:55:07 +02:00 committed by Ivan
parent 0878db4e17
commit 932f31e37b
9 changed files with 108 additions and 11 deletions

View file

@ -666,7 +666,9 @@ error_code cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPa
if (!perm->temp.empty())
{
// Create PARAM.SFO
psf::save_object(fs::file(perm->temp + "/PARAM.SFO", fs::rewrite), perm->sfo);
fs::pending_file temp(perm->temp + "/PARAM.SFO");
temp.file.write(psf::save_object(perm->sfo));
ensure(temp.commit());
// Make temporary directory persistent (atomically)
if (vfs::host::rename(perm->temp, vfs::get(dir), &g_mp_sys_dev_hdd0, false))
@ -684,7 +686,9 @@ error_code cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPa
else if (perm->can_create)
{
// Update PARAM.SFO
psf::save_object(fs::file(vfs::get(dir + "/PARAM.SFO"), fs::rewrite), perm->sfo);
fs::pending_file temp(vfs::get(dir + "/PARAM.SFO"));
temp.file.write(psf::save_object(perm->sfo));
ensure(temp.commit());
}
// Cleanup
@ -806,7 +810,9 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
psf::assign(sfo, fmt::format("TITLE_%02d", i), psf::string(CELL_GAME_SYSP_TITLE_SIZE, setParam->titleLang[i]));
}
psf::save_object(fs::file(vfs::get(dir + "/PARAM.SFO"), fs::rewrite), sfo);
fs::pending_file temp(vfs::get(dir + "/PARAM.SFO"));
temp.file.write(psf::save_object(sfo));
ensure(temp.commit());
}
return CELL_OK;

View file

@ -1306,7 +1306,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
if (!entry.is_directory)
{
if (entry.name == "PARAM.SFO" || entry.name == "PARAM.PFD")
if (entry.name == "."sv)
{
continue;
}
if (entry.name == "PARAM.SFO"sv || entry.name == "PARAM.PFD"sv)
{
continue; // system files are not included in the file list
}
@ -1899,7 +1904,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
// Write all files in temporary directory
auto& fsfo = all_files["PARAM.SFO"];
fsfo = fs::make_stream<std::vector<uchar>>();
psf::save_object(fsfo, psf);
fsfo.write(psf::save_object(psf));
for (auto&& pair : all_files)
{

View file

@ -768,6 +768,13 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
// Preprocess entries
data.back().name = vfs::unescape(data.back().name);
if (!data.back().is_directory && data.back().name == "."sv)
{
// Files hidden from emulation
data.resize(data.size() - 1);
continue;
}
// Add additional entries for split file candidates (while ends with .66600)
while (data.back().name.ends_with(".66600"))
{

View file

@ -1299,8 +1299,10 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
games[m_title_id] = bdvd_dir;
YAML::Emitter out;
out << games;
fs::file(fs::get_config_dir() + "/games.yml.tmp", fs::rewrite).write(out.c_str(), out.size());
fs::rename(fs::get_config_dir() + "/games.yml.tmp", fs::get_config_dir() + "/games.yml", true);
fs::pending_file temp(fs::get_config_dir() + "/games.yml");
temp.file.write(out.c_str(), out.size());
temp.commit();
}
else if (m_cat == "1P" && from_hdd0_game)
{

View file

@ -113,6 +113,8 @@ namespace psf
return result;
}
stream.seek(0);
// Get header
header_t header;
ensure(stream.read(header));
@ -186,8 +188,10 @@ namespace psf
return result;
}
void save_object(const fs::file& stream, const psf::registry& psf)
std::vector<u8> save_object(const psf::registry& psf, std::vector<u8>&& init)
{
fs::file stream = fs::make_stream<std::vector<u8>>(std::move(init));
std::vector<def_table_t> indices; indices.reserve(psf.size());
// Generate indices and calculate key table length
@ -264,6 +268,8 @@ namespace psf
fmt::throw_exception("Invalid entry format (key='%s', fmt=0x%x)", entry.first, fmt);
}
}
return std::move(static_cast<fs::container_stream<std::vector<u8>>*>(stream.release().get())->obj);
}
std::string_view get_string(const registry& psf, const std::string& key, std::string_view def)

View file

@ -53,7 +53,7 @@ namespace psf
registry load_object(const fs::file&);
// Convert PSF registry to SFO binary format
void save_object(const fs::file&, const registry&);
std::vector<u8> save_object(const registry&, std::vector<u8>&& init = std::vector<u8>{});
// Get string value or default value
std::string_view get_string(const registry& psf, const std::string& key, std::string_view def = ""sv);

View file

@ -190,8 +190,9 @@ void emu_settings::SaveSettings()
}
// Save config atomically
fs::file(config_name + ".tmp", fs::rewrite).write(out.c_str(), out.size());
fs::rename(config_name + ".tmp", config_name, true);
fs::pending_file temp(config_name);
temp.file.write(out.c_str(), out.size());
temp.commit();
// Check if the running config/title is the same as the edited config/title.
if (config_name == g_cfg.name || m_title_id == Emu.GetTitleID())