From 133be4d1a87b2e29e510b44070edc5ca35c0e936 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 23 Aug 2026 18:46:09 +0200 Subject: [PATCH] =?UTF-8?q?fix(journal):=20platform-independent=20file-nam?= =?UTF-8?q?e=20sanitisation=20=E2=80=94=20CI=20linux-portable=20red=20sinc?= =?UTF-8?q?e=202c2d57b2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/AcDream.Core/Journal/JournalFile.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/AcDream.Core/Journal/JournalFile.cs b/src/AcDream.Core/Journal/JournalFile.cs index 6cd08331..4fccb059 100644 --- a/src/AcDream.Core/Journal/JournalFile.cs +++ b/src/AcDream.Core/Journal/JournalFile.cs @@ -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. + /// + /// The set is FIXED, not Path.GetInvalidFileNameChars(): 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. /// + 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(); }