fix(journal): platform-independent file-name sanitisation — CI linux-portable red since 2c2d57b2
All checks were successful
CI / linux-portable (push) Successful in 3m10s
CI / windows-gate (push) Successful in 5m41s
CI / release (push) Successful in 2m57s

Path.GetInvalidFileNameChars() is platform-dependent: on Linux it is
only '/' and NUL, so a backslash in a server or character name survived
sanitisation there and JournalFileTests.TheFileNameFollowsRetailsPattern
failed on the Linux runner while passing on Windows. Sanitise against a
fixed set (Windows' printable invalid chars plus all control chars) so
one name maps to one file name on every platform.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-23 18:46:09 +02:00
parent 9cf15e1f13
commit 133be4d1a8

View file

@ -67,13 +67,25 @@ public static class JournalFile
/// Strips anything a file name cannot carry. Retail had no need for this —
/// its server and character names never contained a path separator — but a
/// name is outside data here and must not be able to redirect a write.
///
/// <para>The set is FIXED, not <c>Path.GetInvalidFileNameChars()</c>: that
/// API is platform-dependent (on Linux it is only '/' and NUL), so a
/// backslash survived sanitisation there and the same character produced
/// two different file names on the two CI platforms (linux-portable,
/// 2026-08-23). Windows' set is the strictest of the supported platforms;
/// applying it everywhere keeps one name mapping to one file name.</para>
/// </summary>
private static readonly char[] InvalidFileNameChars =
['"', '<', '>', '|', ':', '*', '?', '\\', '/'];
private static string Sanitize(string value)
{
var text = new StringBuilder(value.Length);
foreach (char c in value)
{
text.Append(Array.IndexOf(Path.GetInvalidFileNameChars(), c) >= 0 ? '_' : c);
bool invalid = c < ' '
|| Array.IndexOf(InvalidFileNameChars, c) >= 0;
text.Append(invalid ? '_' : c);
}
return text.ToString();
}