guest_savedata_delete catches the runtime_error that the PRX raises for null arguments, so the target needs configure_windows_unwind like the other savedata targets that catch; without it the throw terminates the process on MinGW.
NpTrophy reads the trophy count and icons from the title's trophy
package (names are encrypted and stay not implemented), PS4 v1 save data
calls wrap the native v2/v3 ones, and NpWebApi library contexts, handles
and push event filters work offline (service filters fail without a
signed-in user). libSceAjm is built from the libSceAjm.native sources
for PS4 titles. Limbo's (CUSA01664) remaining PS4 imports, including the
synchronous PS4 TUS calls and the Facebook dialog calls next to the
existing libraries, are exported as not implemented.
The NetCtl ApRp calls, the SaveData debug calls, HttpDbgEnableProfile,
HttpDbgSetPrintf, PadEnableExtensionPort and VideoRecording Init, Term
and SendCommand return 0; ImeForTestFunction returns 0x80BC00FF; the Hmd
distortion work memory align and size are 0x400 and 0x20000 and
DistortionGetCompoundEyeCorrectionCommand returns 0x81110009;
AjmInstanceCodecType returns the instance id shifted right by 14.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RbLgECLQ2bpDM7oe2urGZK
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
The PS5 references count save data differently from the PS4: SharpEmu
uses a 64 KiB block, and SharpEmu and KytyPS5 allow 48 to 16384 blocks
per save, which at 64 KiB a block is 3 MiB to 1 GiB, the PS4's byte
range. The module used the PS4 values, 32 KiB blocks and a 32768-block
maximum. At 64 KiB a block, sceSaveDataDirNameSearch and
sceSaveDataGetMountInfo therefore counted up to twice the blocks a
save's files use, and a save without a recorded size reported 32768
blocks, which is 2 GiB.
The search test now expects 64 KiB blocks and the 16384 maximum, and
the block accounting gets its own technical debt entry.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
MinGW libstdc++ up to GCC 16 does not treat a reparse point as a link in
std::filesystem::remove_all, so a host tree that holds a symlink is walked
through the link and never returns. Add RemoveTree, which removes the tree
itself on Windows, and use it where save data, app content and the shader
disk cache removed host trees. The libstdc++ fix is in GCC 17 (88856ad855ae).
sceSaveDataSetSaveDataMemory2 read the whole slot file, patched it and
replaced it through a temporary file on every call, so each call cost a
full rewrite of the slot (up to 32 MiB). The changed ranges now go to a
small journal that is staged through the slot's temporary file and
renamed into place, then written into the slot file in place, and the
journal is removed. A journal left by an interrupted call is replayed by
the next setup, get, set or sync of that slot.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The NID RvID8BVeg+g, declared as sceSaveDataUnknown_RvID8BVeg for
Minecraft (PPSA17221), hashes to sceSaveDataPrepareForTransferring. The
name is not in aerolib; it was found by combining words from the
libSceSaveData names that are. Behaviour is unchanged: it still throws,
now naming the real function.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017WeVmjnnPPKdxVTpr2Vjtw
An unterminated or empty directory name, "." or "..", or a name
containing "/", "\" or ":" now returns SAVE_DATA_ERROR_PARAMETER and
leaves the mount result unchanged. The SDK 12.000 reference lists that
code for an invalid parameter of sceSaveDataMount3, KytyPS5's
SaveDataMount3 returns it for an invalid name, and sceSaveDataDelete
and sceSaveDataConvert already return it here for the same check.
It threw before, which stopped Minecraft Preview (PPSA19639) on
entering a world.
The Mount3 trace now prints at most the 32 bytes of the directory name
and the 16 bytes of the mount point, since both can be unterminated
when the mount fails.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#5173 changes the create condition right after the last error check, and #3950 removes the comment after the create block, so clearing the result in either place made the pull requests conflict. The result is still cleared only after every error return and before anything is written to it.
Every native save reported SAVE_DATA_BLOCKS_MAX blocks, all of them free,
in the sceSaveDataDirNameSearch infos and in sceSaveDataGetMountInfo,
whatever the title created it with and whatever its files held. A save's
size is now the blocks of the sceSaveDataMount3 call that created it,
kept beside the save; a save without a kept size takes that of its next
mount that names one, and otherwise keeps SAVE_DATA_BLOCKS_MAX. Free
blocks are what the save's files leave of it, each file rounded up to
32 KiB blocks, and the blocks and free-blocks sort keys use both.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Animal Well (PPSA22520) checks for its save with a CREATE2 mount it never
unmounts, then saves with a second mount of the same directory. That
mount returns BUSY, and the title keeps using the first mount point for
sceSaveDataPrepare, its save file and sceSaveDataUmount2.
sceSaveDataMount3 cleared the result before its checks, so the save was
written to "/save" in the game folder instead of the save directory, and
the first mount was never released. The result is now written only when
the mount succeeds, as shadPS4 does.
Apple clang ships libc++, which differs from libstdc++ where the sources
relied on it:
- std::atomic<std::shared_ptr<T>> is not provided. AtomicSharedPtr is that
type where the library has it and a mutex-guarded pointer with the same
member functions elsewhere; the AGC driver uses it.
- std::atomic_ref<const T> is not provided; the page span reads go through
a non-const reference.
- std::filesystem::file_time_type::clock::to_sys is not provided;
std::chrono::file_clock::to_sys is.
- std::max and std::min do not deduce across the integer types of the
guest range arithmetic, which is spelled with an explicit type.
- <string> and <initializer_list> are included where the sources and tests
use them.
sceSaveDataDirNameSearch reads % in the directory name pattern as any
run of characters and _ as one character. The matcher stopped when the
name ran out and then required the pattern to have ended too, so a
trailing % with nothing left to match failed: SAVEDATA% did not find a
save named SAVEDATA, and TRAI_% did not find TRAIL. A % now matches no
characters at the end of a name as it already did in the middle.
Minecraft (PPSA17221) fails to load on nine absent imports. The authorized-app
dialog runs the common-dialog state machine without UI and reports the user
as having cancelled, like the login and VR setup dialogs. The other two,
sceNpAuthGetAuthorizedAppCode and the unnamed libSceSaveData.native NID
RvID8BVeg+g, are declared as throwing stubs with unknown signatures.
Co-Authored-By: Claude Fable 5.1 <[email protected]>