fix: derive install paths from RomM folder (fs_name) for folder-based ROMs - #125
Merged
Conversation
… ROMs
Install directory and ROM path were derived from the downloaded file name
rather than the ROM's actual on-disk structure, so:
- Nested single-file ROMs used a folder built from the file name (e.g.
"All-Star Baseball '99 (Europe)") instead of the RomM folder
("All-Star Baseball '99").
- Multi-file ROMs pointed the ROM path at a nonexistent extensionless file
named after the folder instead of a real file inside it.
Both broke IsInstalled detection and the emulator play path (fixes #124).
Thread the ROM folder (fs_name) through the revision/install info and add
folder-aware RomMInstallPaths overloads so paths mirror RomM's layout for
nested-single and multi-file ROMs. For multi-file ROMs the ROM path now
points at the primary real file. Simple single files are unchanged, so
already-downloaded games don't flip to "not installed".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Greptile SummaryThis PR aligns folder-based ROM paths with RomM's filesystem layout. The main changes are:
Confidence Score: 4/5Multi-file imports can still produce nonexistent play paths, and remote folder names can escape the configured install root.
Games/RomMImport.cs and Games/RomMInstallPaths.cs
|
| Filename | Overview |
|---|---|
| Games/RomMImport.cs | Adds folder-aware import paths, but multi-file paths can still point to nonexistent files when metadata is empty or nested. |
| Games/RomMInstallController.cs | Uses the persisted folder name for the download and extraction directory. |
| Games/RomMInstallPaths.cs | Adds folder-aware path helpers without validating that the remote folder remains under the install root. |
| Games/RomMRevisionFactory.cs | Assigns folder metadata for nested single-file and multi-file ROMs while preserving simple-file behavior. |
| Models/RomM/Rom/GameInstallInfo.cs | Carries the folder name into the installation workflow. |
| Models/RomM/Rom/RomMRomLocal.cs | Persists folder metadata in local revision sidecars. |
| RomM.cs | Propagates folder metadata for default and user-selected revisions. |
| RomM.Tests/RomMInstallPathsTests.cs | Covers normal folder pinning and null or empty fallback behavior. |
| RomM.Tests/RomMRevisionFactoryTests.cs | Covers folder metadata for simple, nested, and multi-file ROM shapes. |
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
Games/RomMImport.cs:199-202
**Empty File List Restores Placeholder Path**
When a multi-file ROM has no populated `Files` entries, `SelectPrimaryFile` returns null and this falls back to the extensionless display name in `ROM.Name`. The resulting path does not match any extracted file, so `IsInstalled` remains false and the imported play path cannot launch the game.
### Issue 2 of 3
Games/RomMImport.cs:199-204
**Primary File Loses Relative Path**
When the selected file is below another directory in a multi-file ROM, using only `FileName` constructs `<installDir>/<fileName>` while extraction preserves the nested path. `File.Exists` then checks a nonexistent file and the imported emulator path is invalid.
### Issue 3 of 3
Games/RomMInstallPaths.cs:21-24
**Rooted Folder Escapes Install Root**
`folderName` comes from RomM's `fs_name` and is passed directly to `Path.Combine`. If a malformed or compromised server returns a rooted path, `Path.Combine` discards `rootInstallDir`, allowing the download and archive extraction to write outside the configured mapping.
Reviews (1): Last reviewed commit: "fix: derive install paths from RomM fold..." | Re-trigger Greptile
… root Address code review on the install-path derivation: - Multi-file ROMs now use the primary file's path relative to the ROM folder (RomMRevisionFactory.RelativeFilePath), so a file below a subdirectory matches what extraction writes instead of resolving to <installDir>/<leaf>. - With no file list at all, fall back to fs_name rather than the extensionless display Name. - fs_name and file names come from the server: RomMInstallPaths now refuses rooted values and ".." segments before combining, and the importer skips such a ROM instead of aborting the platform import. - Archive entry names are untrusted too, so extraction resolves every destination through RomMInstallPaths.ResolveWithin (zip slip) rather than handing raw keys to SharpCompress' ExtractFullPath. The 7z path validates entry names up front where the archive can be inspected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Fixes #124.
Problem
The install folder and ROM path were derived from the downloaded file name rather than from RomM's actual on-disk structure (
fs_name), so paths didn't match the real files. This brokeIsInstalleddetection and the emulator play path — most visibly when a mapping points at a mounted RomM library.All-Star Baseball '99/All-Star Baseball '99 (Europe).zip): the folder was built from the file name →All-Star Baseball '99 (Europe)instead of the RomM folderAll-Star Baseball '99.1080 TenEighty Snowboarding/…): the folder was right, but the ROM path pointed at a nonexistent extensionless file…\1080 TenEighty Snowboardinginstead of a real file inside the folder.Fix
Thread the ROM's real folder (
fs_name) through the path computation so paths mirror RomM's layout:RomMRevision/GameInstallInfo— addFolderName(fs_name for folder-based ROMs; null for simple single files, persisted in the sidecar).RomMRevisionFactory— setFolderNamefromfs_nameforhas_nested_single_fileand multi-file ROMs.RomMInstallPaths— folder-awareInstallDir/GamePathoverloads that pin the directory to<root>/<fs_name>when a folder name is present, falling back to the old file-name-derived behavior otherwise.RomMImport— install dir/path useFolderName; for multi-file ROMs the ROM path points at the primary real file (SelectPrimaryFile) instead of the folder placeholder.RomMInstallController/RomM.cs— install/download and sidecar-restore use the same folder-aware computation, keeping import-time and install-time paths in lockstep.Simple single files are intentionally untouched, so already-downloaded games in the common case don't flip to "not installed".
Resulting paths now match disk exactly, e.g.
Z:\roms\n64\All-Star Baseball '99\All-Star Baseball '99 (Europe).zip.Tests
RomMInstallPathsTests— folder-aware overloads + null/empty fallback.RomMRevisionFactoryTests—FolderNamefor simple-single / nested-single / multi-file.Existing tests still pass (the 2-arg overloads remain). Not built locally (this is a .NET Framework project with no
dotnet/msbuildon macOS); theTestsCI workflow links these pure-logic files and will run the suite.🤖 Generated with Claude Code