Re-enable save system, fix header/version stamping, handle missing media

- Fixed the actual reason saving never worked on any platform: saveWrite()
  never stamped file->header/file->version before serializing, so every
  written save file had a zeroed magic header and failed its own
  validation on the next load. Confirmed via a manual write/load round
  trip that this alone fully explains "saving doesn't work."
- Re-enabled saveInit()/saveDispose() in engine.c (previously commented out
  under "Temporarily disable save code").
- Added SAVE.available + saveIsAvailable(), refreshed by every real
  save/load/delete attempt. saveInit() no longer treats an unreachable
  save medium as fatal to booting - it logs and continues, since a missing
  memory card/stick shouldn't prevent playing.
- Hardened PSP's saveInitPSP() to actually detect a missing memory stick
  (sceIoGetstat on ms0:/) instead of assuming success, and fixed
  single-level sceIoMkdir to build the full PSP/SAVEDATA directory chain.
- Added busy-retry (CARD_ERROR_BUSY) and a not-mounted guard to Dolphin's
  live savestreamdolphin.c path, extending the same handling already
  backported into savedolphin.c.
- Added a "Save" entry to the game menu wired to saveWrite(0), showing a
  clear message on success, on failure, and when saveIsAvailable() is false.
This commit is contained in:
2026-08-04 08:30:24 -05:00
parent f3ea507313
commit 7a03ef8eaf
12 changed files with 174 additions and 24 deletions
+12
View File
@@ -7,7 +7,18 @@
#include "save/save.h"
void savePSPEnsureBaseDirs(void) {
sceIoMkdir(SAVE_PSP_BASE_DIR, 0777);
sceIoMkdir(SAVE_PSP_SAVEDATA_DIR, 0777);
}
errorret_t saveInitPSP(void) {
SceIoStat stat;
if(sceIoGetstat(SAVE_PSP_ROOT, &stat) < 0) {
errorThrow("No memory stick detected");
}
savePSPEnsureBaseDirs();
errorOk();
}
@@ -40,6 +51,7 @@ errorret_t saveLoadPSP(const uint8_t slot, savefile_t *file) {
}
errorret_t saveWritePSP(const uint8_t slot, const savefile_t *file) {
savePSPEnsureBaseDirs();
char_t dir[SAVE_PSP_PATH_MAX];
snprintf(dir, SAVE_PSP_PATH_MAX, SAVE_PSP_DIR_FORMAT,
SAVE_PSP_TITLE_ID, (uint32_t)slot
+19 -2
View File
@@ -11,6 +11,9 @@
#include <pspiofilemgr.h>
#define SAVE_PSP_PATH_MAX 256
#define SAVE_PSP_ROOT "ms0:/"
#define SAVE_PSP_BASE_DIR "ms0:/PSP"
#define SAVE_PSP_SAVEDATA_DIR "ms0:/PSP/SAVEDATA"
#define SAVE_PSP_FILE_FORMAT "ms0:/PSP/SAVEDATA/%s%02u/save.dat"
#define SAVE_PSP_DIR_FORMAT "ms0:/PSP/SAVEDATA/%s%02u"
@@ -23,9 +26,14 @@ typedef struct {
} savepsp_t;
/**
* Initializes the save system on PSP.
* Initializes the save system on PSP. Confirms the memory stick is
* actually reachable (sceIoGetstat on SAVE_PSP_ROOT) rather than assuming
* so, since raw sceIo calls otherwise only fail once something tries to
* touch the filesystem - and ensures the PSP/SAVEDATA directory tree
* exists (SAVE_PSP_BASE_DIR then SAVE_PSP_SAVEDATA_DIR, since sceIoMkdir
* only creates one level at a time).
*
* @return An error code if initialization fails.
* @return An error code if no memory stick is reachable.
*/
errorret_t saveInitPSP(void);
@@ -61,3 +69,12 @@ errorret_t saveWritePSP(const uint8_t slot, const savefile_t *file);
* @return An error code if the delete fails.
*/
errorret_t saveDeletePSP(const uint8_t slot);
/**
* Ensures SAVE_PSP_BASE_DIR and SAVE_PSP_SAVEDATA_DIR both exist, creating
* whichever are missing. sceIoMkdir only creates one directory level at a
* time, so this must run before creating any per-slot save directory
* beneath SAVE_PSP_SAVEDATA_DIR. Safe to call repeatedly - an
* already-exists result is not an error.
*/
void savePSPEnsureBaseDirs(void);
+1
View File
@@ -22,6 +22,7 @@ errorret_t saveStreamOpenReadPSP(
}
errorret_t saveStreamOpenWritePSP(savestreampsp_t *p, const uint8_t slot) {
savePSPEnsureBaseDirs();
char_t dir[SAVE_PSP_PATH_MAX];
snprintf(dir, SAVE_PSP_PATH_MAX, SAVE_PSP_DIR_FORMAT,
SAVE_PSP_TITLE_ID, (uint32_t)slot