Repository navigation
Saves named before backslash paths are copied to their new names at mount - #904
Closed
JoseZamoraCifras wants to merge 1 commit into
Closed
JoseZamoraCifras wants to merge 1 commit into
JoseZamoraCifras wants to merge 1 commit into
Conversation
…at mount Builds before 7c23cc0 (backslashes separate path components, PR seedds#513) took a backslash as part of a name, so a game that opens save:\savedata0.bin stored a file named "\savedata0.bin". Since that change the host looks for savedata0.bin, finds nothing, and the save looks lost: The Legend of Zelda: Link's Awakening (01006BB00C6F0000) shows every file of its file select as "New game" while the old files are still in the save folder. At each transactional save mount, right after the work directory is cloned, save_legacy_names clones each entry whose guest name has a backslash (a file, or a directory with its tree) to the path that name names now, makes its parent directories by exact guest name (a case collision gets an alias, as a create does), and marks the old entry with an attribute so that this happens once: a copy the game erases later stays erased. It never overwrites an entry and keeps the old one, which a build before the change still reads. One log line per copy; a name that leads above the save's root, or a copy the disk refuses, logs a red line and is tried again at the next mount. It works in the work directory only, so it rides the save transaction: the copies reach the committed save with the game's own Commit, and a kill or a remount before that leaves the committed save as it was and does the same again. A lookup that falls back to the old name would have had to teach every write, create, rename, delete and listing about it, and an erased file would have come back. Test: dm/host/tests/t_fs_backslash.c (make -C dm/host/tests fs-backslash). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JoseZamoraCifras
added a commit
to JoseZamoraCifras/NX2Apple
that referenced
this pull request
Nov 1, 2026
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>
4 of 6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Builds before 7c23cc0 (#513: backslashes separate path components) took a backslash as part of a name. A game that opens
save:\savedata0.bintherefore stored a file literally named\savedata0.binin its save folder. Since #513 the host looks forsavedata0.bin, finds nothing, and the save looks lost: The Legend of Zelda: Link's Awakening (01006BB00C6F0000) shows every file of its file select as "New game", while\savedata0.bin,\savedata3.bin,\screenshot0.binand\screenshot3.binare still in the folder. Any game that writessave:\...paths is affected the same way.At each transactional save mount, right after the work folder is cloned,
save_legacy_names(hle_fs.c):CLONE_NOFOLLOW) to the path that name names now, making parent folders by exact guest name (a case collision gets a.dm-case-Nalias as a create does)org.d2rmobile.backslash-copied, so this happens once: a file the game erases later stays erasedsave: \savedata0.bin copied to savedata0.bin (...)). A name that leads above the save's root, or a copy the disk refuses, logs a red line, stays unmarked and is tried again at the next mountIt works in the work folder only, so it rides the save transaction. The copies reach the committed save with the game's own
Commit. A kill or a remount before that leaves the committed save as it was and does the same again. The other way, a lookup that falls back to the old name, would have had to teach every write, create, rename, delete and listing about it, and an erased file would have come back.Known limit: a save packed for cloud saves (
save_sync.c) carries only the guest-name attribute, not the mark. A device that receives a save in which the game erased a copied file copies the old entry again.The reference entry is "Saves named by a build before backslash paths" in
docs/reference/services.md, and the game notedm/games/01006BB00C6F0000/README.mdlinks to it. The same change is carried by NX2Apple as a patch: LNPANDY/NX2Apple#461.Checked
make -C dm/host/tests GAME=01006BB00C6F0000 runon this branch (every host test, including the newt_fs_backslash, 26 checks: copies at the root, in folders and below an ordinary folder, no overwrite, case collision, a name above the root, committed save untouched beforeCommit, remount, an erased copy stays erased, a refused copy is retried);python3 -m unittest dm.tools.tests.test_docs. On NX2Apple's tree (the same change on top of its patches) alsomake ... asan(ASan and UBSan, every host test).01006BB00C6F0000, v131072), built with--platform macfrom this change on top of NX2Apple's patches (pin cd859c3, not this branch's base). A save folder holding only\savedata0.bin,\savedata3.bin,\screenshot0.binand\screenshot3.binfrom a build before fs: backslash path separators and 8-byte aligned file handles #513 logs the four copies at mount and no red line, and the file select shows File 1 and the autosave with their old progress 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.hle_fs.c(DM_SAVE).regress.py check --games: not run. The change runs only at a save mount, and does nothing in a save that has no backslash in a name, which covers every game that never wrotesave:\....Docs
docs/reference/<subsystem>.mdentry, andpython3 dm/tools/docs_symptoms.pywas run (the symptom index)dmsh_chain.py --headerwas run anddm/gfx/nvn/dmsh_chain.his part of the change (no chain tool changed)🤖 Generated with Claude Code