From f31d8febbfe62b35d4f259bc1c731cfcd15e70f7 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 15 Dec 2025 23:46:18 +0000 Subject: [PATCH] Handle more of Windows's weird paths AFAICT, any sequence of ".[ .]*" (except from "") is equivalent to "." on Windows. Let's handle that in our path sanitisation code. Fixes #2151. --- .../core/filesystem/FileSystem.java | 26 +++++++------------ .../core/filesystem/FileSystemTest.java | 1 + .../resources/test-rom/spec/apis/fs_spec.lua | 5 ++++ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/projects/core/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/projects/core/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index 509ee63f8..6fb31162f 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/projects/core/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -352,7 +352,7 @@ public class FileSystem { return sanitizePath(path, false); } - private static final Pattern threeDotsPattern = Pattern.compile("^\\.{3,}$"); + private static final Pattern manyDotsPattern = Pattern.compile("^[. ]+$"); // IMPORTANT: Both arrays are sorted by ASCII value. private static final char[] specialChars = new char[]{ '"', '*', ':', '<', '>', '?', '|' }; @@ -376,27 +376,19 @@ public class FileSystem { for (var fullPart : Splitter.on('/').split(path)) { var part = fullPart.strip(); - if (part.isEmpty() || part.equals(".") || threeDotsPattern.matcher(part).matches()) { - // . is redundant - // ... and more are treated as . - continue; - } + // Limit part length to 255. + if (part.length() > 255) part = part.substring(0, 255).strip(); if (part.equals("..")) { // .. can cancel out the last folder entered - if (!outputParts.isEmpty()) { - var top = outputParts.peekLast(); - if (!top.equals("..")) { - outputParts.removeLast(); - } else { - outputParts.addLast(".."); - } - } else { + if (outputParts.isEmpty() || outputParts.peekLast().equals("..")) { outputParts.addLast(".."); + } else { + outputParts.removeLast(); } - } else if (part.length() >= 255) { - // If part length > 255 and it is the last part - outputParts.addLast(part.substring(0, 255).strip()); + } else if (part.isEmpty() || (part.startsWith(".") && manyDotsPattern.matcher(part).matches())) { + // Skip empty paths, ".", or any other sequence of "[. ]+" (as this is also treated as "." on Windows). + continue; } else { // Anything else we add to the stack outputParts.addLast(part); diff --git a/projects/core/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java b/projects/core/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java index 90f67a9b5..56284f60a 100644 --- a/projects/core/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java +++ b/projects/core/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java @@ -89,6 +89,7 @@ public class FileSystemTest { new String[]{ "a/./b", "a/b" }, new String[]{ "a/../b", "b" }, new String[]{ "a/.../b", "a/b" }, + new String[]{ "a/. ./b", "a/b" }, new String[]{ " a ", "a" }, new String[]{ "a b c", "a b c" }, }; diff --git a/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua b/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua index 05fc9c849..b5e256084 100644 --- a/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -156,6 +156,11 @@ describe("The fs library", function() expect(fs.combine("a", "../../c")):eq("../c") end) + it("handles weird Windows paths", function() + expect(fs.combine("a", "...")):eq("a") + expect(fs.combine("a", ". .")):eq("a") + end) + it("combines empty paths", function() expect(fs.combine("a")):eq("a") expect(fs.combine("a", "")):eq("a")