Files
AnyPS5/docs/dev/debt/libSceSaveData.native.md
T
juanpimg 2f0ed638dc feat(prx): declare the missing PS5 3.20 system exports
AnyPS5 resolves a title's imports by NID, so a title that imports a system
function no library provides fails to load with an unresolved import. The
PS5 3.20 export inventory lists 193 such exports across 37 PS5 system
libraries AnyPS5 implements but does not provide.

Declare them as throwing stubs so those titles load and reach their next
blocker. Each declaration calls NotImplemented_nid_no_patch and returns 0;
none of them implements the function. Declarations with a credible
prototype use it and cite the source with a pinned commit, and the rest
are declared without parameters, which resolves the import without making
an ABI claim. The technical-debt files record the limitation per library.

libSceMbus and libSceSystemService are left out because pull request #7821
declares them. libSceAgc is left out because its exports are versioned, so
the 3.20 NID names a different symbol from the one AnyPS5 ships.
libSceAvPlayer.native is left out because it compiles libSceAvPlayer's
Export.cpp.

Names and NIDs come from the PS5 3.20 export inventory at
https://github.com/DNNDHH/PS5-3.20_Libs/tree/b2a77c09cd71c01f34c790cfbe98c751a13262ad
2026-10-19 23:16:55 +02:00

9.1 KiB

libSceSaveData.native technical debt

Unknown function info

  • sceSaveDataCreateTransactionResource, sceSaveDataDeleteTransactionResource (libSceSaveData.native) - transaction resources return synthetic positive identifiers and validate initialization state; resource parameter validation and transactional rollback semantics on host filesystem storage are unknown
  • sceSaveDataPrepareForTransferring (libSceSaveData.native, NID RvID8BVeg+g) - declared without parameters as a throwing stub; Minecraft (PPSA17221) imports it beside sceSaveDataTransferringMountPs4 and sceSaveDataDirNameSearchPs4 and fails to load without it. The name hashes to the NID but is not in aerolib; it was found by combining words from the libSceSaveData names in aerolib. Its arguments and behaviour are unknown.
  • sceSaveDataTransferringMountPs4, sceSaveDataDirNameSearchPs4 (libSceSaveData.native) - arguments assumed to be those of sceSaveDataTransferringMount and sceSaveDataDirNameSearch: KytyPS5 binds both NIDs to the PS5 functions, and prosper captured the same result layout on a title for the search. There is no PS4 save area, so the mount returns NOT_FOUND and the search reports zero hits
  • sceSaveDataConvert (libSceSaveData.native) - the parameter block (user id at +0x00, SceSaveDataDirName pointer at +0x08, 48 opaque bytes after it) is read from PPSA28416's single call, not confirmed by KytyPS5, shadPS4, fpPS4 or SharpProspero, which have no body for it. Host saves have no size limit, so an existing save returns SCE_OK without touching its files and no event is queued; what the console returns for a save that is mounted, already converted or needs no conversion is unknown. The directory name is validated as sceSaveDataDelete does
  • sceSaveDataGetConvertProgress (libSceSaveData.native) - imported by PPSA16064; signature and error codes follow the SDK 12.000 reference (float* progress). Save data conversion on host filesystems completes synchronously, so the progress query returns SAVE_DATA_OK with the last conversion's progress (0.0f before any conversion or when conversion fails, 1.0f after successful conversion), SAVE_DATA_ERROR_PARAMETER if progress is null, or SAVE_DATA_ERROR_NOT_INITIALIZED when the library is uninitialized; intermediate asynchronous conversion progress on console is unmeasured
  • sceSaveDataCancel (libSceSaveData.native) - imported by PPSA23126, which fails to load without it; added without an implementation because its signature is unknown. Every save data call here finishes before it returns, so nothing is ever in flight to cancel, but what the console returns then is unknown
  • sceSaveDataDirNameSearch (libSceSaveData.native) - the sort keys (0 directory name, 1 user parameter, 2 blocks, 3 modification time, 5 free blocks) and orders (0 ascending, 1 descending) follow shadPS4, not a hardware run; saves with equal keys keep directory-name order before a descending reverse. A save's size is the blocks of the sceSaveDataMount3 call that created it, kept beside the save in <dir>.blocks; a save without a kept size takes that of its next mount that names one, and otherwise reports SAVE_DATA_BLOCKS_MAX. The search infos (blocks, free blocks and 32 reserved bytes per returned name, following shadPS4's OrbisSaveDataSearchInfo), sceSaveDataGetMountInfo and the two block keys use that size and, as free, what the save's files leave of it, each file rounded up to 32 KiB blocks; the console's file system overhead is not known and not counted. Keys other than 0, 1, 2, 3 and 5 (including 4) and orders above 1 return SCE_SAVE_DATA_ERROR_PARAMETER; shadPS4 and KytyPS5 only reject keys above 5, so key 4 is rejected here because no source names it. In the directory name pattern % matches any run of characters, none included, and _ exactly one, as the comments of shadPS4's matcher describe; also not confirmed on hardware
  • sceSaveDataInitialize3 (libSceSaveData.native) - a repeated initialize succeeds: PPSA12544's executable and its Unity SaveData plugin both initialize, and the plugin fails on any error. Initializations are counted and sceSaveDataTerminate ends the session at the last one; how the console pairs them is unknown
  • sceSaveDataCheckIpmiIfSize, sceSaveDataDebug, sceSaveDataDebugCheckBackupData, sceSaveDataDebugCleanMount, sceSaveDataDebugCompiledSdkVersion, sceSaveDataDebugCreateSaveDataRoot, sceSaveDataDebugProspero, sceSaveDataDebugRemoveSaveDataRoot and sceSaveDataDebugTarget (libSceSaveData.native) - names and NIDs are present in the PS5 3.20 export inventory. The seven no-argument prototypes follow the PS4 stubs in shadPS4, not measured on a console; no credible prototypes were found for the other two. All declarations have no parameters solely to resolve known imports and make no ABI claim.

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.

  • 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

  • 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

  • sceSaveDataGetMountInfo, sceSaveDataGetParam (libSceSaveData.native) - null pointer arguments return SAVE_DATA_ERROR_PARAMETER instead of throwing C++ exceptions; 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