Files
AnyPS5/docs/dev/debt/libSceSaveData.native.md
T

20 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

  • sceSaveDataCheckBackupData, sceSaveDataRestoreBackupData, sceSaveDataUmountWithBackup (libSceSaveData.native) - not measured on a PS5: the block layouts, error checks and behaviour follow shadPS4's PS4 binding (check, restore, unmount with backup), and the tests check that binding, not the console. sceSaveDataBackup still copies nothing, so the check and the restore see only backups that sceSaveDataUmountWithBackup made.

  • sceSaveDataUmountWithBackup (libSceSaveData.native) - an unknown mount point returns SAVE_DATA_ERROR_NOT_MOUNTED, as sceSaveDataUmount2 does, where shadPS4 returns SAVE_DATA_ERROR_NOT_FOUND. The backup is copied before the call returns, so SAVE_DATA_ERROR_BACKUP_BUSY never occurs, and the UMOUNT_BACKUP event is queued at once, as fpPS4 does; a failed copy sets its error to SAVE_DATA_ERROR_INTERNAL, as shadPS4's backup thread does.

  • sceSaveDataCheckBackupData, sceSaveDataRestoreBackupData (libSceSaveData.native) - saves keep no icons, so the check never fills icon, as shadPS4 does without icon0.png, and another title's titleId returns SAVE_DATA_ERROR_NOT_FOUND because only the running title's saves are kept. Backups live in _sd_backup/<dir name>, outside the save, and sceSaveDataDelete removes one with its save, as shadPS4's backup inside the save directory goes with it; whether the console keeps a deleted save's backup is unknown.

  • 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