How Apollo Save Tool Integrates with the Orbis SaveData API for PS4 Save Mounting

Apollo Save Tool uses a two-layer C wrapper in source/saves.c and source/sd.c to call sceFsMountSaveData and sceFsUmountSaveData, decrypting sealed keys and sandboxing mounts under /data/apollo/mount/ before exposing PS4 save data as a standard filesystem.

The Apollo Save Tool (bucanero/apollo-ps4) provides homebrew utilities for managing PlayStation 4 save files by integrating directly with Sony's Orbis SaveData API. Understanding how Apollo Save Tool integrates with the Orbis SaveData API reveals the cryptographic and filesystem layers required to mount encrypted PS4 save data as accessible directories.

Architecture Overview

Apollo implements a clean separation between high-level save management and low-level Orbis kernel calls. The high-level logic resides in source/saves.c, handling sandbox creation, SQLite metadata tracking, and user-facing functions like orbis_SaveMount() and orbis_SaveUmount(). The low-level implementation in source/sd.c contains the cryptographic wrappers that invoke the actual Orbis FS syscalls sceFsMountSaveData() and sceFsUmountSaveData().

Mounting PS4 Save Data with the Orbis API

The mount operation follows a strict sequence to ensure encrypted save images are properly decrypted and isolated before user access.

Building the Sandbox Environment

Before calling the kernel, orbis_SaveMount() constructs a unique sandbox directory under APOLLO_SANDBOX_PATH (/data/apollo/mount/%s/). This path serves as the mount point where the decrypted filesystem will appear. The function ensures the directory exists and is empty, preventing cross-contamination between different save operations.

Handling Sealed Keys and Encryption

Apollo must decrypt the sealed key stored alongside the save image before the kernel can mount it. Inside mountSave() (source/sd.c), the tool reads the .bin key file and calls decryptSealedKeyAtPath() to extract the raw decryption key. This key is passed directly to the Orbis FS layer and is never written to disk unencrypted.

Calling sceFsMountSaveData

With the sandbox ready and key decrypted, mountSave() initializes the mount options structure via sceFsInitMountSaveDataOpt(), sets the budget ID to "system", and executes:

sceFsMountSaveData(&opt, volumePath, mountPath, decryptedSealedKey);

This syscall attaches the encrypted save image (located at volumePath) to the sandbox directory (mountPath), transparently decrypting it and exposing the contents as standard files.

Unmounting Save Data Safely

Unmounting reverses the mount process while ensuring data integrity. The orbis_SaveUmount() function in source/saves.c reconstructs the sandbox path and delegates to umountSave() in source/sd.c.

Inside umountSave(), the code initializes unmount options with sceFsInitUmountSaveDataOpt() and calls:

sceFsUmountSaveData(&opt, mountPath, handle, ignoreErrors);

This detaches the filesystem, flushes any pending writes to the encrypted image, and invalidates the mount point. Apollo then cleans up the sandbox directory to free resources.

Alternative API for Application Settings

While sceFsMountSaveData handles user save data, Apollo uses the higher-level Orbis SaveData API for its own configuration. In source/settings.c, the tool calls sceSaveDataMount2() and sceSaveDataUmount() to manage the savedata.db SQLite database and binary config files. This API abstracts away the sealed-key mechanics, making it suitable for simple app-specific storage rather than complex encrypted save images.

Code Example: Mounting and Unmounting in Practice

The following pattern demonstrates the complete lifecycle as implemented in the Apollo Save Tool:

#include "saves.h"

/* Mount a PS4 save */
save_entry_t *save = find_save_by_title_id("CUSA12345");
char mount_path[ORBIS_SAVE_DATA_DIRNAME_DATA_MAXSIZE];

if (orbis_SaveMount(save, SAVE_FLAG_PS4, mount_path)) {
    LOG("Save mounted at: %s", mount_path);
    
    /* Perform file operations on the decrypted save data */
    /* ... */
    
    /* Unmount when finished */
    if (orbis_SaveUmount(mount_path)) {
        LOG("Save unmounted successfully");
    } else {
        LOG("Unmount failed");
    }
} else {
    LOG("Mount failed");
}

This example reflects the actual API surface in source/saves.c, handling both the mount path output and proper cleanup.

Key Source Files in the Apollo Repository

Understanding the Orbis SaveData API integration requires examining these specific files in the bucanero/apollo-ps4 repository:

  • source/saves.c – Contains orbis_SaveMount() and orbis_SaveUmount(), handling sandbox path construction, SQLite metadata updates, and delegation to low-level helpers.
  • source/sd.c – Implements mountSave() and umountSave(), wrapping sceFsMountSaveData() and sceFsUmountSaveData() with sealed-key decryption.
  • include/saves.h – Defines public structures like save_entry_t and mount flags (SAVE_FLAG_PS4, SAVE_FLAG_TROPHY, SAVE_FLAG_LOCKED).
  • source/settings.c – Demonstrates the alternative sceSaveDataMount2() API for Apollo's internal configuration storage.
  • include/settings.h – Contains app_config_t structure definitions for settings management.

Summary

  • Apollo Save Tool integrates with the Orbis SaveData API through a two-layer C wrapper that separates high-level save management from kernel filesystem calls.
  • Mounting involves creating sandbox directories under /data/apollo/mount/, decrypting sealed keys via decryptSealedKeyAtPath(), and invoking sceFsMountSaveData() to attach encrypted save images.
  • Unmounting uses sceFsUmountSaveData() to detach filesystems and flush data, followed by sandbox cleanup in orbis_SaveUmount().
  • The repository uses the higher-level sceSaveDataMount2() API in source/settings.c for application-specific configuration storage.
  • All operations are implemented in source/saves.c and source/sd.c within the bucanero/apollo-ps4 repository.

Frequently Asked Questions

What is the difference between sceFsMountSaveData and sceSaveDataMount2?

sceFsMountSaveData is a low-level filesystem API that mounts encrypted save images directly using decrypted sealed keys, requiring manual sandbox management. sceSaveDataMount2 is a higher-level API that abstracts key handling and mounting into a single call, used primarily for application settings rather than user save data manipulation.

How does Apollo Save Tool handle encrypted PS4 save files?

Apollo decrypts the sealed key stored alongside the save image using decryptSealedKeyAtPath() in source/sd.c. This decrypted key is passed to sceFsMountSaveData(), which transparently decrypts the save image and exposes it as a standard directory under /data/apollo/mount/.

Where does Apollo Save Tool store mounted save data temporarily?

Mounted saves are isolated in sandbox directories under /data/apollo/mount/<save_id>/, defined as APOLLO_SANDBOX_PATH. This ensures each save is mounted in an isolated environment and prevents conflicts between different save operations.

What happens if the save file doesn't exist when mounting?

When the ORBIS_SAVE_DATA_MOUNT_MODE_CREATE2 flag is set and the key file is missing, orbis_SaveMount() calls createSave() to generate a new encrypted save image and inserts a corresponding entry into the local savedata.db SQLite database before proceeding with the mount operation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →