sceIoDread hands back a dirent whose d_private holds the 8.3 short name
ahead of the long name, and we never wrote the short name at all - the game
got whatever was on the stack there. Crazy Taxi: Fare Wars reads it rather
than d_name, so it rejected every file in ms0:/MUSIC, ended up with an empty
playlist and never even reserved an mp3 handle: custom soundtracks were
silently dead, with the game spinning on InitResource/SetLoopNum forever.
Generate the names from the directory listing, and resolve them back in
DirectoryFileSystem so a game can open a file by the short name it was given.
Both sides come from the same function, so they agree.
We can't lean on the host for any of this. Linux, macOS and Android have no
8.3 names at all, and while Windows does keep aliases it generates them by a
different rule - it counts to ~4 and then switches to a hash - so resolution
runs before the literal path is tried rather than as a fallback, or on
Windows we'd quietly open a different file than the one we handed the game.
The exact names a real PSP produces are still unverified - no pspautotest
covers d_private - so this implements the ordinary FAT rule and the new
FatShortNames unit test pins that down until hardware can settle it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>