From 8de1239132dc572e41c6dbec72f6619a3ba2504b Mon Sep 17 00:00:00 2001 From: RipleyTom Date: Tue, 3 Sep 2019 02:39:24 +0200 Subject: [PATCH] Simulate BSD FS for file order presentation in savedata --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 60 ++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 7033c4aec2..7b7e819735 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -813,6 +813,13 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v lv2_sleep(ppu, 250); + // Check if RPCS3_BLIST section exist in PARAM.SFO + // This section contains the list of files in the save ordered as they would be in BSD filesystem + std::vector blist; + + if (psf.count("RPCS3_BLIST")) + blist = fmt::split(psf.at("RPCS3_BLIST").as_string(), {"/"}, false); + // Get save stats { fs::stat_t dir_info{}; @@ -849,11 +856,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v u32 size_kbytes = 0; + std::vector files_sorted; + for (auto&& entry : fs::dir(dir_path)) { entry.name = vfs::unescape(entry.name); - // only files, system files ignored, fileNum is limited by setBuf->fileListMax if (!entry.is_directory) { if (entry.name == "PARAM.SFO" || entry.name == "PARAM.PFD") @@ -861,6 +869,29 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v continue; // system files are not included in the file list } + files_sorted.push_back(entry); + } + } + + // clang-format off + std::sort(files_sorted.begin(), files_sorted.end(), [&](const fs::dir_entry& a, const fs::dir_entry& b) -> bool + { + const auto a_it = std::find(blist.begin(), blist.end(), a.name); + const auto b_it = std::find(blist.begin(), blist.end(), b.name); + + if (a_it == blist.end() && b_it == blist.end()) + { + // Order alphabetically for old saves + return a.name.compare(b.name); + } + + return a_it < b_it; + }); + // clang-format on + + for (auto&& entry : files_sorted) + { + { statGet->fileNum++; size_kbytes += (entry.size + 1023) / 1024; // firmware rounds this value up @@ -1135,6 +1166,25 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v const u32 access_size = std::min(fileSet->fileSize, fileSet->fileBufSize); + // clang-format off + auto add_to_blist = [&](const std::string& to_add) + { + if (std::find(blist.begin(), blist.end(), to_add) == blist.end()) + { + if(auto it = std::find(blist.begin(), blist.end(), ""); it != blist.end()) + *it = to_add; + else + blist.push_back(to_add); + } + }; + + auto del_from_blist = [&](const std::string& to_del) + { + if (auto it = std::find(blist.begin(), blist.end(), to_del); it != blist.end()) + *it = ""; + }; + // clang-format on + switch (const u32 op = fileSet->fileOperation) { case CELL_SAVEDATA_FILEOP_READ: @@ -1184,6 +1234,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v file.trunc(sr + wr); fileGet->excSize = ::narrow(wr); all_times.erase(file_path); + add_to_blist(file_path); has_modified = true; break; } @@ -1195,6 +1246,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v psf.erase("*" + file_path); fileGet->excSize = 0; all_times.erase(file_path); + del_from_blist(file_path); has_modified = true; break; } @@ -1213,6 +1265,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v const u64 wr = file.write(fileSet->fileBuf.get_ptr(), access_size); fileGet->excSize = ::narrow(wr); all_times.erase(file_path); + add_to_blist(file_path); has_modified = true; break; } @@ -1238,6 +1291,11 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v fmt::throw_exception("Failed to create directory %s (%s)", new_path, fs::g_tls_error); } + // add file list per FS order to PARAM.SFO + std::string final_blist; + final_blist = fmt::merge(blist, "/"); + psf::assign(psf, "RPCS3_BLIST", psf::string(final_blist.size(), final_blist)); + // Write all files in temporary directory auto& fsfo = all_files["PARAM.SFO"]; fsfo = fs::make_stream>();