mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
Persist SaveDataMemory2 save data to disk (fixes Astro Bot progress not saving) (#659)
* Persist save-data memory across restarts * Fix SetSaveDataMemory2 data loss, split saves per user, add atomic writes everywhere - SaveDataSetSaveDataMemory2 treated data_num=0 as "no entries" even when a valid data pointer was supplied. Astro Bot calls this with data_num=0 meaning "one entry, at data[0]" (an implicit-count convention), so every real save write from it was silently dropped as a no-op. Default data_num to 1 when data is non-null, matching that convention. - SaveDataSetupSaveDataMemory2/Get/SetSaveDataMemory2 rejected any call that included a non-null icon pointer. Icon persistence isn't implemented, but titles are allowed to pass one anyway; rejecting the whole call over it made every title that does so fail outright. Ignore icon instead of rejecting. - SaveDataMount3/SaveDataTransferringMount/SaveDataDelete built their save-data path from title+dir_name only, dropping the user_id PS5 local users are keyed by (unlike the newer SetSaveDataMemory2 layout, which already nests by user_id). Nest these under user_id too so saves from different local users can no longer collide. No migration for the old flat layout - the project is still pre-release/experimental. - Classic SaveDataMount3-mounted titles (Blasphemous, Dead Cells, ...) write their save files directly through the guest's normal file I/O once mounted, bypassing SaveData's own write path entirely, so they had none of the crash-safety SetSaveDataMemory2 already had. Added the same protection at the file-system layer: a guest file opened under a /savedataN mount that recreates the file from scratch (O_CREAT and/or O_TRUNC) is now written to a .tmp shadow file and atomically replaces the real one on close, instead of being truncated in place. - Both write paths now back up the file they're about to replace into a sibling "backups" folder (same filename, no added suffix) before the atomic replace, so a manual recovery copy of the previous save always survives a write - even one that "succeeds" but wasn't wanted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix save-memory compatibility and preserve existing saves --------- Co-authored-by: nmzik <Nmzik@mail.ru> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -89,6 +89,33 @@ void CheckSaveRename(const std::filesystem::path &root,
|
||||
"renamed save contents");
|
||||
}
|
||||
|
||||
void TestSaveOpenVisibility() {
|
||||
constexpr char Path[] = "/savedata0/visible-save.dat";
|
||||
constexpr char Payload[] = "saved progress";
|
||||
|
||||
const int fd = FileSystem::KernelOpen(Path, 0xa01, 0777);
|
||||
Check(fd >= 3, "create save file exclusively");
|
||||
FileSystem::FileStat stat {};
|
||||
Check(FileSystem::KernelStat(Path, &stat) == OK && stat.st_size == 0,
|
||||
"created save file is visible before close");
|
||||
Check(FileSystem::KernelOpen(Path, 0xa01, 0777) ==
|
||||
Libs::LibKernel::KERNEL_ERROR_EEXIST,
|
||||
"exclusive creation detects an open save file");
|
||||
Check(FileSystem::KernelWrite(fd, Payload, sizeof(Payload) - 1) ==
|
||||
sizeof(Payload) - 1,
|
||||
"populate save file before truncation");
|
||||
Check(FileSystem::KernelClose(fd) == OK, "close populated save file");
|
||||
Check(FileSystem::KernelStat(Path, &stat) == OK &&
|
||||
stat.st_size == sizeof(Payload) - 1,
|
||||
"save file contains the truncation fixture");
|
||||
|
||||
const int truncated = FileSystem::KernelOpen(Path, 0x401, 0777);
|
||||
Check(truncated >= 3, "truncate existing save file");
|
||||
Check(FileSystem::KernelStat(Path, &stat) == OK && stat.st_size == 0,
|
||||
"save truncation is visible before close");
|
||||
Check(FileSystem::KernelClose(truncated) == OK, "close truncated save file");
|
||||
}
|
||||
|
||||
void CheckMountRoot(const std::filesystem::path &root) {
|
||||
Common::File cache;
|
||||
Check(cache.Create(root / "rpf.cache"), "create directory listing fixture");
|
||||
@@ -390,6 +417,7 @@ int main() {
|
||||
CheckDirectoryStream(temporary.Path());
|
||||
CheckAprPaths(temporary.Path());
|
||||
FileSystem::Mount(temporary.Path(), "/savedata0");
|
||||
TestSaveOpenVisibility();
|
||||
CheckSaveRename(temporary.Path(), "first-save");
|
||||
CheckSaveRename(temporary.Path(), "replacement-save");
|
||||
FileSystem::Shutdown();
|
||||
|
||||
Reference in New Issue
Block a user