Commit Graph
170 Commits
Author SHA1 Message Date
Dean e60b0e0c31 Merge pull request #8630 from Ondra97/codex/fix-savedata-icon-persistence
fix(savedata): persist native save icons
2026-11-05 08:19:12 +13:00
zaryabzip c5e2f0ed94 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/savedata-initialize2
# Conflicts:
#	docs/dev/debt/libSceSaveData.native.md
2026-11-03 07:43:23 +05:00
Ondra97 ab8360ee1e fix(savedata): validate mount points before icon access 2026-11-03 00:04:24 +01:00
Yunus Shaikh 4de3c5975a Merge #12748's main merge into feat/libSceSaveData-event-callbacks 2026-11-02 08:32:28 -08:00
Dean Galvin 02af078a35 Merge commit 'b28bb772177768f99874ca38f6252cd0139acf2a' into HEAD
# Conflicts:
#	docs/dev/debt/libSceSaveData.native.md
2026-11-03 05:19:45 +13:00
Dean 662fac8333 Merge pull request #12853 from slopgobblercobbler/fix/savedata-mount-point-termination
fix(libSceSaveData.native): validate mount point termination in mount operations
2026-11-03 05:14:36 +13:00
Dean Galvin 23493d9ca3 Merge commit '24238c4cb1a58e4ddb0596e68dc072e715f9bb17' into HEAD
# Conflicts:
#	docs/dev/debt/libSceSaveData.native.md

The pending declarations line keeps main's sceSaveDataGetProgress split and drops the three names this branch implements (sceSaveDataCheckBackupData, sceSaveDataRestoreBackupData, sceSaveDataUmountWithBackup).
2026-11-03 01:02:45 +13:00
Yunus Shaikh df0b6d335c Merge main into feat/libSceSaveData-event-callbacks
# Conflicts:
#	docs/dev/debt/libSceSaveData.native.md
2026-11-02 03:03:25 -08:00
Dean cb0f84e398 Merge pull request #10674 from MarcZX10/marc/signatures-libscesavedata
feat(libSceSaveData): declare sceSaveDataGetProgress with its known signature
2026-11-02 23:23:40 +13:00
Ondra97 d154e94cca fix(savedata): retain host-space coverage during icon refresh 2026-11-01 16:52:39 +01:00
Yunus Shaikh 62ab6243cb Merge feat/savedata-backup-progress-sourced into feat/libSceSaveData-event-callbacks 2026-11-01 06:54:26 -08:00
Dean Galvin 9b9e850d90 Merge commit 'd8b60b46ed425b117b6fae18900fe6ab81ed6661' into HEAD
# Conflicts:
#	core/libs/prx/libSceSaveData.native/Export.cpp
2026-11-02 03:23:34 +13:00
Dean d94fad17de Merge pull request #8285 from DealPotato/feat/savedata-mount2
feat(savedata): add sceSaveDataMount2
2026-11-02 03:22:25 +13:00
slopgobblercobbler 6f7f6dc1b6 fix(libSceSaveData.native): validate mount point termination in mount operations 2026-11-01 15:18:39 +01:00
MarcZX10 c480d90bd8 feat(libSceSaveData): declare sceSaveDataGetProgress with its known signature
It still throws through NotImplemented_nid_no_patch; the parameter is the
float* of the OpenOrbis headers and shadPS4.
2026-10-31 22:27:14 +00:00
MarcZX10 5b7ba8484a Merge remote-tracking branch 'upstream/main' into feat/host-free-space
# Conflicts:
#	core/libs/prx/libSceSaveData.native/Export.cpp
2026-10-31 00:26:47 +00:00
Yunus Shaikh 36b5e96eb1 Merge feat/savedata-backup-progress-sourced into feat/libSceSaveData-event-callbacks 2026-10-30 23:09:35 +00:00
Yunus Shaikh 842f75d7e0 Merge main into feat/savedata-backup-progress-sourced
JJenkx's #13324 gives isMountedDirectory an std::error_code parameter.
The merge passes one in checkBackupData and restoreBackupData and
returns SAVE_DATA_ERROR_INTERNAL on a host error, as main's callers do.

GuestSaveDataMountStatus.cpp: CheckBackups writes param.json where
ResolvePath_nid_no_patch puts /app0/sce_sys/param.json, not under the
working directory. #13324's CheckHostMountFailures now resolves the
first guest path from its mount-host-failures subdirectory, so /app0
maps there, and checkBackupData didn't find the title's param.json.
2026-10-30 23:09:34 +00:00
Adrià 6472c708ae Merge pull request #13324 from JJenkx/fix/savedata-mount-host-failure
fix(savedata): keep failed host mounts unpublished
2026-10-30 21:46:41 +01:00
Yunus Shaikh 0d0abe09c1 fix(libSceSaveData): start the event delivery thread at the first registration
sceSaveDataInitialize3 started the callback delivery thread for every
title that initializes save data, though nearly none register a
callback, and could throw there if scePthreadCreate failed. The thread
now starts at the first successful sceSaveDataRegisterEventCallback of
an initialization, under the calling, g_slots_mutex and callbacks.mutex
locks that registration already takes, so a title that never registers
gets no thread and sceSaveDataInitialize3 is again only the count.
A replacing registration, one from inside a callback and one after an
unregister reuse the running thread; a refused one starts nothing.

The last sceSaveDataTerminate still takes the worker out under
g_slots_mutex and joins it outside the lock, and only when one was
started, so a session that registers between that terminate's detach
and its join starts its own thread.

The tests run two sessions with no registration, and on Linux count the
process's threads to check that Initialize3 and a refused registration
start none, that the first registration starts one and later ones reuse
it, and that the final terminate joins it.
2026-10-30 19:39:06 +00:00
MarcZX10 10fe6196e2 feat(libSceSaveData.native): bound a save's free blocks by the host volume
With ANYPS5_FREE_SPACE=host, sceSaveDataGetMountInfo and the directory-name
search report a save's free blocks as the smaller of its own free blocks and
the 64 KiB blocks the save's volume still has. A full volume reports none
free, so a title that checks for room sees the same answer the create check
gives. Unset, the free blocks stay the save's own.
2026-10-30 18:48:57 +00:00
MarcZX10 4385554953 feat(libSceSaveData.native): refuse a new save the host volume cannot hold
With ANYPS5_FREE_SPACE=host, creating a save first checks the free space of
the save directory's volume against the save's size, 16384 blocks when the
title passes none. A save that does not fit fails with NO_SPACE_FS and
reports the blocks missing in required_blocks, and no directory is made.
If the volume cannot be queried, the create keeps today's behaviour and one
line goes to stderr. Opening an existing save and the default fixed mode are
unchanged.
2026-10-30 18:48:56 +00:00
MarcZX10 0a27bb9dd9 feat(libSceSaveData.native): validate ANYPS5_FREE_SPACE at every save mount
Every sceSaveDataMount3 call reads ANYPS5_FREE_SPACE and stops the title with
an error naming the variable when it is not fixed or host. Unset keeps
today's behaviour, so no save is created differently by default.
2026-10-30 18:48:56 +00:00
Yunus Shaikh bc6b4d76f9 fix(libSceSaveData): register the event callback atomically with the final terminate
sceSaveDataRegisterEventCallback read g_initializations before it took
any lock. A registration that read a nonzero count could then store its
callback after the final sceSaveDataTerminate had set the count to zero
and cleared the callback, return OK with no delivery thread, and have
the next Initialize3 deliver events to a callback the terminate had
dropped.

Registration now checks the count and stores the callback under
g_slots_mutex, the lock the final terminate holds while it reaches zero
and detaches delivery. It takes the calling lock first, the order the
delivery thread already uses when a callback calls back into SaveData,
so a terminate from inside the callback is still BUSY and the terminate
joins the delivery thread outside both locks.

The new case races registration against the final terminate on two
guest threads for 200 iterations, holding the delivery thread in a
callback on every other one so a registration that passed its check
waits across the whole terminate. Each must end NOT_INITIALIZED, or OK
with the callback cleared, and a backup after Initialize3 must not reach
the raced callback.
2026-10-30 18:38:00 +00:00
JJenkx 2606c33532 fix(savedata): report host mount errors without unwinding 2026-10-30 14:08:25 -04:00
Adrià f91137142e Merge pull request #13027 from Celegans12/feat/savedata-inventory-exports-20261030
feat(savedata): add missing cloud and sync inventory exports
2026-10-30 13:45:45 +01:00
JJenkx 0c110bdf8e fix(savedata): keep failed host mounts unpublished 2026-10-30 08:12:24 -04:00
Ondra97 398fb1891d chore(savedata): reconcile icon persistence with current main 2026-10-30 11:42:55 +01:00
zaryabzip 8197ab33fd Merge remote-tracking branch 'origin/main' into feat/savedata-initialize2
# Conflicts:
#	docs/dev/debt/libSceSaveData.native.md
2026-10-30 15:09:23 +05:00
Yunus Shaikh 629477b800 feat(libSceSaveData): deliver backup completions to a registered event callback
sceSaveDataRegisterEventCallback and sceSaveDataUnregisterEventCallback
were parameterless declarations that threw. They now follow shadPS4
#5226: registering before initialization is NOT_INITIALIZED, a null
callback is PARAMETER, a second registration replaces the callback and
its userdata, and unregistering needs no initialization.

Every backup completion that queues an event for
sceSaveDataGetEventResult, type 2 from sceSaveDataBackup and type 1 from
sceSaveDataUmountWithBackup, is queued for polling first and then handed
to the callback registered at that moment. A library thread delivers it:
sceSaveDataInitialize3 starts it with scePthreadCreate, as
libSceUsbStorage starts its monitor, so the callback runs on a guest
thread, and the last sceSaveDataTerminate joins it. Unregistering waits
for a running callback and drops completions not yet delivered, and a
terminate from inside the callback returns BUSY instead of joining its
own thread, as shadPS4 does.

guest_savedata_event_callback covers the errors, both event types, the
delivering thread, unregistration, replacement, a terminate from inside
the callback and an idle terminate followed by a restart.
2026-10-30 09:57:33 +00:00
Yunus Shaikh 46c8ff27a6 Merge main into feat/savedata-backup-progress-sourced
# Conflicts:
#	core/libs/tests/GuestSaveDataMountStatus.cpp
#	docs/dev/debt/libSceSaveData.native.md
2026-10-29 22:05:12 -07:00
Adrià 0d62a3e0db Merge pull request #12699 from SnekPolylepis/feat/savedata-mounted-count-and-lifecycle
feat(libSceSaveData): add provisional abort and clear progress stubs
2026-10-30 05:51:21 +01:00
Yunus Shaikh 22291cddd8 Merge main into feat/savedata-backup-progress-sourced
# Conflicts:
#	core/libs/tests/GuestSaveDataMountStatus.cpp
#	docs/dev/debt/libSceSaveData.native.md
2026-10-29 18:59:33 -07:00
Adrià f67988f8e8 Merge pull request #12644 from slopgobblercobbler/fix/savedata-backup-dir-name-validation
fix(libSceSaveData.native): validate directory name in sceSaveDataBackup
2026-10-30 02:52:13 +01:00
Codex 2299b471cb feat(savedata): retain seven inventory exports within reviewed scope 2026-10-30 03:22:06 +02:00
Codex d058e59ffd feat(savedata): add missing cloud and sync inventory exports 2026-10-30 00:20:59 +02:00
SnekPolylepis e64a9b14ef Merge main into SaveData lifecycle branch 2026-10-29 09:54:32 -05:00
SnekPolylepis 8436d54350 fix(savedata): leave mounted count unimplemented 2026-10-29 09:52:50 -05:00
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
Adrià 50b6ea0dc5 Merge pull request #12444 from BunnyFl/fix/savedata-memory-host-write
fix(libSceSaveData): hold a host write over save memory reads into guest buffers
2026-10-29 12:56:55 +01:00
slopgobblercobbler 43dc8a75c7 fix(libSceSaveData.native): validate directory name in sceSaveDataBackup 2026-10-29 11:34:09 +01:00
Yunus Shaikh 9429d8395b fix(libSceSaveData): keep save and backup paths inside their roots
Before any copy or delete, the backup and the restore check the roots
they use (_sd, _sd_backup and their staging and old directories) and
every entry under them for the save: each must be a plain directory or
file, not a symbolic link, or on Windows a reparse point such as a
junction, and must stay under its root after weakly_canonical. Anything
else makes the restore return SAVE_DATA_ERROR_INTERNAL, and the backup
report it in its event, with nothing changed. sceSaveDataCheckBackupData
checks the backup the same way. The copies walk the tree themselves and
refuse a link instead of following it.
2026-10-29 10:13:16 +00:00
Yunus Shaikh 1744dbf5ab fix(libSceSaveData): put the old backup back when the backup swap fails, and flush before removing it
backupSave moved the previous backup to _sd_backup_old and then renamed
the new copy into place; when that rename failed, the save had no
backup until the next one. A failed rename now moves the previous
backup back into _sd_backup and removes the staged copy. Every staged
file is flushed before the swap (FlushFileBuffers on Windows, fsync on
POSIX, as libc does), and on POSIX the directories on both sides of
each rename are flushed too, all before the previous backup is removed.
2026-10-29 10:09:29 +00:00
Yunus Shaikh 637b601bfb fix(libSceSaveData): restore a backup through a staged copy and roll back a failed swap
sceSaveDataRestoreBackupData used to remove the live save's files and
copy the backup over them, so a copy that failed half way left neither.
It now copies the backup, its .param and its blocks file to
_sd_restore_tmp/<dir>, checks that the copy has every entry at its size,
and flushes it. Then it moves the live save, .param and blocks file to
_sd_restore_old/<dir>, moves the staged copy into place and removes the
old one. A failed move puts back everything already moved, so the live
save stays as it was. The staging roots sit next to _sd, not in it,
where sceSaveDataDirNameSearch would list them.

SaveDataSetFileStepHook_nid_no_patch sets a function that is called
before each copy and rename of the backup and restore paths with a step
name and the path written; when it returns false that step fails. It
does nothing unless a test sets it.
2026-10-29 10:08:24 +00:00
Yunus Shaikh 26a50dd0fd fix(libSceSaveData): validate backup metadata before Check and Restore read it
sceSaveDataCheckBackupData and sceSaveDataRestoreBackupData now read a
backup through one check that runs before anything in the live save
changes. A backup directory without a save inside, a missing .param, a
.param that is not exactly one SaveDataParam, or a blocks entry that is
not a file returns SAVE_DATA_ERROR_INTERNAL, whether or not the caller
asked for param. Before, the check threw on a wrong-sized .param, and
the restore removed the live save's files before finding the .param
missing.
2026-10-29 10:06:11 +00:00
Zain 7016a894f7 feat(libSceSaveData): implement sceSaveDataGetMountedSaveDataCount, sceSaveDataAbort, and sceSaveDataClearProgress 2026-10-28 21:39:18 -05:00
JJenkxandClaude Opus 5.5 1f8b81f3cd fix(libSceSaveData): read a save directory's time natively on Windows
When a save has no stored mtime, its parameters fall back to the save
directory's modification time. On Windows std::filesystem reads that
through the UCRT stat call, which converts through local time using TZ,
so with a TZ other than the Windows zone, including one libc applies
from the guest environment, the reported time was off by the
difference between the zones. The fallback now reads the time with
GetFileAttributesExW. guest_savedata_search checks it under TZ values
12 hours either side of UTC.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 21:12:20 -04:00
zaryabzip bc6a5e4ea1 feat(libSceSaveData): initialize through sceSaveDataInitialize2 2026-10-29 04:16:14 +05:00
Yunus Shaikh 5fed277cf2 feat(libSceSaveData): implement sceSaveDataCheckBackupData, sceSaveDataRestoreBackupData and sceSaveDataUmountWithBackup 2026-10-28 21:18:18 +00:00
ionut27001 a21f985dcf fix(libSceSaveData.native): answer sceSaveDataCancel before initialization as measured in a PS5 payload 2026-10-28 15:37:18 +01:00