Files
AnyPS5/core/libs/prx/libSceSaveData.native/SaveData.hpp
T
OverkillLabs 77ed5e6d0c feat(savedata): mount aliasing, wildcard search, memory slots, async events
Rework the local SaveData implementation into a general-purpose, title-agnostic
backend used by both the native library and the standard libSceSaveData path:

- Directory aliasing: long save directory names are hashed into short mount
  point aliases (persisted to disk) so they fit the SDK's fixed-size mount
  point buffer, with the aliases reversed on directory search.
- Wildcard directory-name search (%/_ patterns) with sorting and optional
  reverse order, matching the DirNameSearch contract.
- Save-data "memory" slots: small per-user, per-slot blobs the title can
  set up, read and write without mounting a directory, backed by files under
  the save root with a companion parameter blob, size and range validation
  on every access, and a dirty flag consulted on commit.
- Async-flavored operations (backup, commit, memory sync) that queue
  SaveDataEvent records consumed through GetEventResult and can be bound to
  kernel event flags, plus transaction-resource and cancel/abort bookkeeping.
- Atomic file writes (temp file + rename) so a mid-write crash never leaves a
  torn save on disk, and corrected/duplicated SDK error code constants.
- Local storage app-status get/set/delete and transferring-mount support for
  PS4-to-PS5 style save transfers.

The native library keeps its own lighter-weight mount/memory implementation
(short "/_sm/<slot>" mount point aliases via the path-alias table) while
gaining the same per-user memory-slot separation, atomic writes and bounds
checking; the two implementations were merged by hand where upstream had
independently touched the native Export.cpp in the same area (backup/event
queue, short mount points) to keep both sets of improvements.

None of this is game-specific: it is a general local save-data backend that
works for any title and tolerates any user id.
2026-09-28 12:48:09 +03:00

67 lines
2.1 KiB
C++

#ifndef CORE_LIBS_PRX_LIBSCESAVEDATANATIVE_SAVEDATA_HPP
#define CORE_LIBS_PRX_LIBSCESAVEDATANATIVE_SAVEDATA_HPP
#include <array>
#include <cstdint>
#include <string>
constexpr int SAVE_DATA_OK = 0;
// Values follow the SDK error table (0x809F0000 + code): 2 OUT_OF_MEMORY, 3 BUSY, 4 NOT_MOUNTED, 7 EXISTS, 8 NOT_FOUND, 0xB INTERNAL, 0xC MOUNT_FULL.
constexpr int SAVE_DATA_ERROR_PARAMETER = -2137063424;
constexpr int SAVE_DATA_ERROR_NOT_INITIALIZED = -2137063423;
constexpr int SAVE_DATA_ERROR_ALREADY_INITIALIZED = -2137063419; // 0x809F0005
constexpr int SAVE_DATA_ERROR_OUT_OF_MEMORY = -2137063422;
constexpr int SAVE_DATA_ERROR_BUSY = -2137063421;
constexpr int SAVE_DATA_ERROR_NOT_MOUNTED = -2137063420;
constexpr int SAVE_DATA_ERROR_MOUNT_FULL = -2137063412;
constexpr int SAVE_DATA_ERROR_EXISTS = -2137063417;
constexpr int SAVE_DATA_ERROR_NOT_FOUND = -2137063416;
constexpr int SAVE_DATA_ERROR_INTERNAL = -2137063413; // 0x809F000B
constexpr int SAVE_DATA_ERROR_MEMORY_NOT_READY = -2137063406; // 0x809F0012
constexpr std::uint32_t SAVE_DATA_MOUNT_MODE_RDONLY = 1;
constexpr std::uint32_t SAVE_DATA_MOUNT_MODE_RDWR = 2;
constexpr std::uint32_t SAVE_DATA_MOUNT_MODE_CREATE = 4;
constexpr std::uint32_t SAVE_DATA_MOUNT_MODE_CREATE2 = 32;
constexpr std::uint64_t SAVE_DATA_BLOCKS_MAX = 32768;
constexpr std::size_t SAVE_DATA_MOUNT_SLOTS = 16;
struct MountSlot {
bool used = false;
std::string mount_point;
std::string real_path;
};
inline std::array<MountSlot, SAVE_DATA_MOUNT_SLOTS> g_slots;
inline int find_slot_by_mount_point(const char* mount_point) {
for (int i = 0; i < static_cast<int>(SAVE_DATA_MOUNT_SLOTS); i++) {
if (g_slots[i].used && g_slots[i].mount_point == mount_point) {
return i;
}
}
return -1;
}
inline int find_free_slot() {
for (int i = 0; i < static_cast<int>(SAVE_DATA_MOUNT_SLOTS); i++) {
if (!g_slots[i].used) {
return i;
}
}
return -1;
}
inline bool any_slot_used() {
for (const auto& s : g_slots) {
if (s.used) {
return true;
}
}
return false;
}
#endif