Files
AnyPS5/docs/dev/debt/libSceSaveData.native.md
Adrià 5a88858805 Merge pull request #11720 from ionut27001/fix/savedata-cancel-not-initialized
fix(libSceSaveData.native): answer sceSaveDataCancel before initialization as measured in a PS5 payload
2026-10-29 12:57:24 +01:00

19 KiB

libSceSaveData.native technical debt

Silent stubs

  • sceSaveDataPrepare, sceSaveDataCommit (libSceSaveData.native) return success without looking at their arguments; what preparing and committing a mounted save do on a console is unknown. The same six titles call both; this counts tests of the result in the three instructions after each call. sceSaveDataPrepare has 11 call sites: PPSA01494, PPSA30839 and PPSA31162 test none of them there, PPSA03984 takes an error path when it is negative, PPSA34502 checks it at one of two sites and PPSA36591 at two of four. sceSaveDataCommit has 14: PPSA01494 and PPSA30839 test none, PPSA03984 and PPSA31162 check its sign, PPSA34502 checks it at all five sites and PPSA36591 at two of four. A failure code from either would change the save flow of the titles that check it, while the stubs keep all six on the success path.

Unknown function info

Functional

  • sceSaveDataDirNameSearch, sceSaveDataDirNameSearch2 (libSceSaveData.native) - only the running title's saves are kept, so a search with another title's title_id reports zero hits, as shadPS4 and KytyPS5 do when that title has no save directory; what a console returns for another title's saves is not verified. The running title's ID is the titleId in its param.json

  • sceSaveDataDirNameSearch2 (libSceSaveData.native) runs the same search as sceSaveDataDirNameSearch with the same condition and result structures, as SharpEmu does, its only source; what distinguishes it on the console is unknown. One title (PPSA35669, in a plugin) disassembled for this entry has one call site (0x2eda71); it clears 56 bytes for the result structure first (the size of the structure used here), puts a value returned by a call with the argument 0x8000 at offset 8 and 0x400 at offset 0x10, and afterwards branches on a negative result and reads the 32-bit field at offset 0, skipping its loop when it is 0. That agrees with the result structure of sceSaveDataDirNameSearch. The condition structure was not read.

  • sceSaveDataMount3 (libSceSaveData.native) - a failed mount (BUSY, EXISTS, NOT_FOUND, MOUNT_FULL) leaves the result as it was, as shadPS4 does; not checked on hardware. Animal Well (PPSA22520) depends on it: it checks for its save with a mount it never unmounts, then saves with a second mount of the same directory, ignores its BUSY and keeps using the first mount point for sceSaveDataPrepare, its file and sceSaveDataUmount2. In PPSA05347 the function that calls it at 0x235fbb5 zeroes its 0x40-byte result before the call and, for a negative result other than 0x809f0008 and 0x809f000f (BUSY included), logs the code and returns it without recording the mount; no abort follows.

  • sceSaveDataMount3 (libSceSaveData.native) - an unterminated or empty directory name, ., .., or a name containing /, \ or : returns SAVE_DATA_ERROR_PARAMETER, which the SDK 12.000 reference lists for an invalid parameter, and leaves the result as it was, as KytyPS5 does. The SDK lets an application use only letters, digits, -, . and @ in a name, and KytyPS5 also accepts _ (valid_path_component); which other names the console's mount rejects is not checked on hardware

  • sceSaveDataBackup, sceSaveDataConvert, sceSaveDataDelete, sceSaveDataDirNameSearch, sceSaveDataDirNameSearchPs4, sceSaveDataGetEventResult, sceSaveDataGetMountInfo, sceSaveDataGetParam, sceSaveDataLoadIcon, sceSaveDataMount, sceSaveDataMount3, sceSaveDataSaveIcon, sceSaveDataSetParam, sceSaveDataUmount2 (libSceSaveData.native) - null pointer arguments return SAVE_DATA_ERROR_PARAMETER instead of throwing C++ exceptions, an implementation assumption matching guest error expectations not checked on hardware; unmounted targets return SAVE_DATA_ERROR_NOT_MOUNTED, and parameter type or buffer size violations return SAVE_DATA_ERROR_PARAMETER after slot lookup

  • sceSaveDataSyncSaveDataMemory (libSceSaveData.native) - validates library initialization and parameters; since in-memory saves flush synchronously on write, sync confirms existence and readiness of the memory blob