Skip to content

Games keep the saves an older engine named \savedata0.bin (patch 0056) - #461

Closed
JoseZamoraCifras wants to merge 3 commits into
LNPANDY:mainfrom
JoseZamoraCifras:claude/interesting-easley-6f427b
Closed

JoseZamoraCifras wants to merge 3 commits into
LNPANDY:mainfrom
JoseZamoraCifras:claude/interesting-easley-6f427b

Conversation

@JoseZamoraCifras

@JoseZamoraCifras JoseZamoraCifras commented Nov 1, 2026 •

Copy link
Copy Markdown

Fix or feature

  • Fix
  • Feature

What and why

After a rebuild on the engine pin of #444, which includes upstream 7c23cc0 (backslashes separate path components), The Legend of Zelda: Link's Awakening (01006BB00C6F0000) showed every file of its file select as "New game". The save was not lost. Builds before 7c23cc0 took the backslash in save:\savedata0.bin as part of the name, so the save folder (~/Library/Application Support/nxnative/<title ID>/save) holds files named \savedata0.bin, \savedata3.bin, \screenshot0.bin and \screenshot3.bin. The new host looks for savedata0.bin and finds nothing. Mario Kart 8, Wonder, Galaxy 2, DKC Tropical Freeze and Mario vs. DK had no such names on the Mac where it was found. Any game that writes save:\... paths is affected the same way.

Patch 0056 (fs: saves named before backslash paths are copied to their new names at mount) copies each such entry to the name it has now when the save is mounted:

  • in the transaction's work folder (save.work), so the copy reaches save only with the game's own Commit, and a kill before that leaves the committed save as it was
  • never over an existing file, and the old entry stays (an older build still reads it)
  • once: the old entry gets the attribute org.d2rmobile.backslash-copied, so a file the game erases later stays erased
  • one log line per copy: save: \savedata0.bin copied to savedata0.bin (...)

The Mac and the iOS app both mount saves through hle_fs.c (DM_SAVE), so both are covered. The device save (<DM_SAVE>_device) is covered too. The reference entry is "Saves named by a build before backslash paths" in docs/reference/services.md, with the one limit it has (cloud saves do not carry the mark).

The patch says Upstream-Status: pending: this PR does not send the change to seedds/nxnative, a maintainer can forward it. The Issue: line names this PR. The number 0056 is free on main today.

Checked

  • Tests: make -C engine/dm/host/tests GAME=01006BB00C6F0000 run (all host tests, including the new t_fs_backslash, 26 checks), make ... asan (ASan and UBSan, all host tests), python3 -m unittest dm.tools.tests.test_docs in engine/, python3 tools/engine.py check (35 patches apply to cd859c3). The same commit, cherry-picked onto seedds/nxnative main, passes t_fs_backslash, t_fs, t_fs_case and the doc tests there.
  • Run on a Mac: Link's Awakening (01006BB00C6F0000, update v131072) built with --platform mac from this engine (shader chain b7cd656abd7c), Apple silicon, macOS 26. The save folder held only \savedata0.bin, \savedata3.bin, \screenshot0.bin and \screenshot3.bin from a build before 7c23cc0. The log shows the four copies at mount and no red line. The file select shows File 1 (Dampé's Hut, 27-10-2026 21:43) and the autosave (Tal Tal Heights, 21:41) instead of "New game". After the game's Commit the committed save holds both names, the copies are byte for byte the old files, and the old entries carry the mark.
  • Not checked: clang-tidy (no LLVM clang-tidy on this Mac, CI runs it upstream), an iPhone run.

Screenshots

None, no visible change.

Scope

  • No engine file (dm/, scripts/, docs/, ref/) is added to the repository: a change there is a patch in patches/ (a commit in engine/, then tools/engine.py export, and tools/engine.py check passes), with its Upstream-Status
  • A fix to the engine or a game profile also goes to seedds/nxnative as a PR in parallel: this PR's patch says forwarded seedds/nxnative#..., or pending until that PR is open (not sent from here: the patch says pending, a maintainer can forward it)
  • A change to a launcher view has before and after screenshots above (this PR changes no launcher view)
  • No keys, game files or data extracted from a game in the change or the attachments

🤖 Generated with Claude Code

Upstream 7c23cc0 (in the pin since LNPANDY#444) turns a backslash in a guest path
into a slash. Builds before it stored save:\savedata0.bin as a file named
"\savedata0.bin", so after a rebuild The Legend of Zelda: Link's Awakening
found no save and showed every file as "New game".

The patch copies each such entry to the name it has now when the save is
mounted, in the transaction's work folder, never over an existing file, and
once. The same change goes to seedds/nxnative.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the patch-queue Changes the patch queue or the upstream pin label Nov 1, 2026
JoseZamoraCifras and others added 2 commits November 1, 2026 20:14
The same change is open upstream as seedds/nxnative#904, and the patch's
Issue line names this pull request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The upstream pull request is closed: the change is not sent to
seedds/nxnative from here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@v0lumehi

v0lumehi commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the fix and for the careful write-up, @JoseZamoraCifras. I read the patch and ran the tests. The copy is safe: it works in the work folder, never overwrites a file and keeps the old entry. I found no case that loses or damages a save.

Some points for the docs and the patch:

  • If both \dir and dir exist, the old folder is not merged. The files stay, but the game cannot see them.
  • A name that leads above the root logs a red line at every mount. It could be marked as done after the first time.
  • Without APFS or free space no copy happens, and the save mounts read-only for that session. A line in the reference entry would help.

The number 0056 is free on main today, but #438, #440 and #372 also carry a 0056. Whoever merges second renumbers, so nothing for you to do.

Two questions:

seedds added a commit to seedds/nxnative that referenced this pull request Nov 4, 2026
…Awakening no longer shows New Game for a file it has

Since 7c23cc0 a backslash in a guest path separates components. Hosts before it took the backslash in save:\savedata0.bin as part of the name, so the save folder holds \savedata0.bin, and today's host looks for savedata0.bin. No path a game can ask for reaches the old file, so the save reads as empty. Link's Awakening (SDK 8.2) names its files this way, and every file of its file select shows New Game.

Each mount of a committed save now renames such entries to the names the game asks for (save_old_names, hle_fs.c): \dir\f becomes dir/f with its folder made, and \dir and dir merge. It goes by guest names, so \Foo beside foo stays a file of its own. A rename is atomic and keeps the contents, and a kill partway is finished by the next mount, so it needs no transaction and no marker, and a file the game erases later stays erased. It runs after the cloud's save came in and under the locks the cloud sender's clone takes. An entry whose new name is taken, or that would leave its folder, stays as it is, with a log line at each mount.

Checked: t_fs section 9, 16 checks, 10 of them fail without the fix; all host tests, and under ASan and UBSan. On Link's Awakening on the Mac (update 1.1.0, headless), a save the game wrote, renamed to the old form: every file New Game without the fix; File 1 with Link, his hearts and his screenshot with it, the file's checksum unchanged. Through a cloud folder: a host without the fix sends the old name, the fixed host renames it as it comes in, the renamed save goes out, and the next mount is in step. Not checked: an iPhone run, clang-tidy (not on this Mac). regress.py check --quick on Link's Awakening passes its shader chain checks but boots nothing (no change to the chain); the runs above are the game runs.

Diagnosed in LNPANDY/NX2Apple#461 by Jose Zamora Cifras, whose patch copies the files and marks them; this one renames instead and shares no code with it.

Front-ends: break: a host with this renames a pre-7c23cc0 save at mount, so a build from before 7c23cc0 can no longer read it; a patch carrying such saves forward (NX2Apple's patch of #461) is no longer needed.

Co-authored-by: Jose Zamora Cifras <44040559+JoseZamoraCifras@users.noreply.github.com>
Know-It-All-Brother pushed a commit to Know-It-All-Brother/nxnative that referenced this pull request Nov 9, 2026
…Awakening no longer shows New Game for a file it has

Since 871ff84 a backslash in a guest path separates components. Hosts before it took the backslash in save:\savedata0.bin as part of the name, so the save folder holds \savedata0.bin, and today's host looks for savedata0.bin. No path a game can ask for reaches the old file, so the save reads as empty. Link's Awakening (SDK 8.2) names its files this way, and every file of its file select shows New Game.

Each mount of a committed save now renames such entries to the names the game asks for (save_old_names, hle_fs.c): \dir\f becomes dir/f with its folder made, and \dir and dir merge. It goes by guest names, so \Foo beside foo stays a file of its own. A rename is atomic and keeps the contents, and a kill partway is finished by the next mount, so it needs no transaction and no marker, and a file the game erases later stays erased. It runs after the cloud's save came in and under the locks the cloud sender's clone takes. An entry whose new name is taken, or that would leave its folder, stays as it is, with a log line at each mount.

Checked: t_fs section 9, 16 checks, 10 of them fail without the fix; all host tests, and under ASan and UBSan. On Link's Awakening on the Mac (update 1.1.0, headless), a save the game wrote, renamed to the old form: every file New Game without the fix; File 1 with Link, his hearts and his screenshot with it, the file's checksum unchanged. Through a cloud folder: a host without the fix sends the old name, the fixed host renames it as it comes in, the renamed save goes out, and the next mount is in step. Not checked: an iPhone run, clang-tidy (not on this Mac). regress.py check --quick on Link's Awakening passes its shader chain checks but boots nothing (no change to the chain); the runs above are the game runs.

Diagnosed in LNPANDY/NX2Apple#461 by Jose Zamora Cifras, whose patch copies the files and marks them; this one renames instead and shares no code with it.

Front-ends: break: a host with this renames a pre-871ff84 save at mount, so a build from before 871ff84 can no longer read it; a patch carrying such saves forward (NX2Apple's patch of seedds#461) is no longer needed.

Co-authored-by: Jose Zamora Cifras <44040559+JoseZamoraCifras@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch-queue Changes the patch queue or the upstream pin

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants