Skip to content

fix: derive install paths from RomM folder (fs_name) for folder-based ROMs - #125

Merged
gantoine merged 2 commits into
mainfrom
fix/issue-124-install-paths
Jul 26, 2026
Merged

fix: derive install paths from RomM folder (fs_name) for folder-based ROMs#125
gantoine merged 2 commits into
mainfrom
fix/issue-124-install-paths

Conversation

@gantoine

Copy link
Copy Markdown
Member

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 broke IsInstalled detection and the emulator play path — most visibly when a mapping points at a mounted RomM library.

  • Nested single file (e.g. 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 folder All-Star Baseball '99.
  • Multiple files (e.g. 1080 TenEighty Snowboarding/…): the folder was right, but the ROM path pointed at a nonexistent extensionless file …\1080 TenEighty Snowboarding instead 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 — add FolderName (fs_name for folder-based ROMs; null for simple single files, persisted in the sidecar).
  • RomMRevisionFactory — set FolderName from fs_name for has_nested_single_file and multi-file ROMs.
  • RomMInstallPaths — folder-aware InstallDir/GamePath overloads 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 use FolderName; 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.
  • RomMRevisionFactoryTestsFolderName for 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/msbuild on macOS); the Tests CI workflow links these pure-logic files and will run the suite.

🤖 Generated with Claude Code

… 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>
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR aligns folder-based ROM paths with RomM's filesystem layout. The main changes are:

  • Persists fs_name as revision and install metadata.
  • Uses folder-aware paths during import and installation.
  • Selects a real file as the play path for multi-file ROMs.
  • Adds tests for folder assignment and path fallback.

Confidence Score: 4/5

Multi-file imports can still produce nonexistent play paths, and remote folder names can escape the configured install root.

  • Empty file metadata falls back to an extensionless placeholder.
  • Nested primary files lose their relative directory.
  • Rooted folder values can redirect filesystem writes.

Games/RomMImport.cs and Games/RomMInstallPaths.cs

Security Review

The new folder-aware path accepts the remote fs_name without checking that the normalized destination remains under the configured install root. A rooted value can redirect downloads and extraction outside that root.

Important Files Changed

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.

Fix All in Claude Code

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

Comment thread Games/RomMImport.cs Outdated
Comment thread Games/RomMImport.cs
Comment thread Games/RomMInstallPaths.cs Outdated
… 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>
@gantoine
gantoine merged commit 466b7ea into main Jul 26, 2026
5 checks passed
@gantoine
gantoine deleted the fix/issue-124-install-paths branch July 26, 2026 21:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] pathing issues for imported games

1 participant