Skip to content

Save games cannot be loaded on non-Windows builds #3235

Description

@bobtista

Prerequisites

  • I have searched for similar issues and confirmed this is not a duplicate

Game Version

  • Command & Conquer Generals
  • Command & Conquer Generals: Zero Hour

Bug Description

On non-Windows builds a save game cannot be loaded. The load reads the save, throws while reading the CHUNK_GameStateMap block, and GameState::loadGame returns SC_INVALID_DATA, so the game returns to the shell instead of entering the save.

GameState::portableMapPathToRealMapPath builds the real path, validates it, and then lowercases the result before returning it:

portable   save\defcon6.map
returned   /home/user/.local/share/command and conquer generals zero hour data/save/defcon6.map

GameStateMap::xfer then passes that lowercased path to GameState::isInSaveDirectory, which compares it against the real Save directory:

save dir   /home/user/.local/share/Command and Conquer Generals Zero Hour Data/Save/

The first validation inside portableMapPathToRealMapPath succeeds, because it runs before the lowercasing. The later check in GameStateMap::xfer fails, because Save is not save on a case sensitive file system, and the block throws.

This is a regression from #1058. Before that change isInSaveDirectory compared case insensitively:

Bool GameState::isInSaveDirectory(const AsciiString& path) const
{
	return path.startsWithNoCase(getSaveDirectory());
}

#1058 replaced that with FileSystem::isPathInDirectory, which compares case insensitively only on Windows. The lowercasing in portableMapPathToRealMapPath and the check in GameStateMap::xfer are both original code and unchanged since the initial commit.

The failure is silent in a release build, because loadGame catches the exception with catch( ... ) and the DEBUG_CRASH that names the failing block is compiled out.

Reproduction Steps

  1. On a non-Windows build, start a mission or skirmish and save the game.
  2. Load that save from the in-game load menu.
  3. Observe the game does not enter the save and returns to the shell.
  4. Repeat on a Windows build. The save loads.

Additional Context

  • The default user data directory name is mixed case (GlobalData.cpp, leaf name Command and Conquer Generals Zero Hour Data), so this affects a default installation rather than only unusual paths.
  • isInSaveDirectory is also used by the restart path and by map name checks in GameLogic, which receive the same lowercased name.
  • FileSystem::isPathInDirectory itself should stay case sensitive off Windows. [GEN][ZH] Fix security issue in map transfer by validating file paths when creating real paths from portable paths #1058 added it to validate network supplied portable paths before a transferred file is written, so relaxing it globally would weaken that check.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething is not working right, typically is user facing

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions