This is an automated email from the ASF dual-hosted git repository.

jt2594838 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 3d98ea5fd78 Fix Windows path segment validation (#17868)
3d98ea5fd78 is described below

commit 3d98ea5fd7876c4f8f96033457824f10842100c8
Author: Caideyipi <[email protected]>
AuthorDate: Tue Jun 9 12:28:44 2026 +0800

    Fix Windows path segment validation (#17868)
    
    * Fix Windows reserved device name validation
    
    * Reject additional illegal Windows path segments
    
    * Reject empty directory path segments
---
 .../apache/iotdb/commons/i18n/UtilMessages.java    |  1 +
 .../apache/iotdb/commons/i18n/UtilMessages.java    |  1 +
 .../org/apache/iotdb/commons/utils/FileUtils.java  |  3 ++
 .../apache/iotdb/commons/utils/WindowsOSUtils.java | 47 +++++++++++++++++-----
 .../apache/iotdb/commons/utils/FileUtilsTest.java  |  8 ++++
 .../iotdb/commons/utils/WindowsOSUtilsTest.java    | 12 ++++++
 6 files changed, 61 insertions(+), 11 deletions(-)

diff --git 
a/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/UtilMessages.java
 
b/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/UtilMessages.java
index 39f4a6ce931..b13ad217f7a 100644
--- 
a/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/UtilMessages.java
+++ 
b/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/UtilMessages.java
@@ -87,6 +87,7 @@ public final class UtilMessages {
       "Renamed file {} to {} because it already exists in the target 
directory: {}";
   public static final String COPIED_FILE_ALREADY_EXISTS =
       "Copy file {} to {} because it already exists in the target directory: 
{}";
+  public static final String ILLEGAL_EMPTY_PATH = "The path cannot be empty. ";
   public static final String ILLEGAL_PATH_DOTS_OR_SEPARATORS =
       "The path cannot be '.', '..', './' or '.\\'. ";
 
diff --git 
a/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/UtilMessages.java
 
b/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/UtilMessages.java
index 8fcc938dbfc..f4215f6e449 100644
--- 
a/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/UtilMessages.java
+++ 
b/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/UtilMessages.java
@@ -85,6 +85,7 @@ public final class UtilMessages {
       "已将文件 {} 重命名为 {},因为目标目录 {} 中已存在同名文件";
   public static final String COPIED_FILE_ALREADY_EXISTS =
       "已将文件 {} 复制为 {},因为目标目录 {} 中已存在同名文件";
+  public static final String ILLEGAL_EMPTY_PATH = "路径不能为空。 ";
   public static final String ILLEGAL_PATH_DOTS_OR_SEPARATORS =
       "路径不能为 '.'、'..'、'./' 或 '.\\\\'. ";
 
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
index e178e2f6047..be99503a3c9 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
@@ -568,6 +568,9 @@ public class FileUtils {
   }
 
   public static String getIllegalError4Directory(final String path) {
+    if (path == null || path.isEmpty()) {
+      return UtilMessages.ILLEGAL_EMPTY_PATH;
+    }
     if (path.equals(".") || path.equals("..") || path.contains("/") || 
path.contains("\\")) {
       return UtilMessages.ILLEGAL_PATH_DOTS_OR_SEPARATORS;
     }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/WindowsOSUtils.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/WindowsOSUtils.java
index 3e8155ed759..d9b2aa2dfa9 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/WindowsOSUtils.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/WindowsOSUtils.java
@@ -23,15 +23,27 @@ import org.apache.tsfile.external.commons.lang3.SystemUtils;
 
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Locale;
 import java.util.Set;
 
 public class WindowsOSUtils {
   private static final String ILLEGAL_WINDOWS_CHARS = "\\/:*?\"<>|";
   private static final Set<String> ILLEGAL_WINDOWS_NAMES =
-      new HashSet<>(Arrays.asList("CON", "PRN", "AUX", "NUL", "COM1-COM9, 
LPT1-LPT9"));
+      new HashSet<>(
+          Arrays.asList(
+              "CON",
+              "PRN",
+              "AUX",
+              "NUL",
+              "COM\u00B9",
+              "COM\u00B2",
+              "COM\u00B3",
+              "LPT\u00B9",
+              "LPT\u00B2",
+              "LPT\u00B3"));
 
   static {
-    for (int i = 0; i < 10; ++i) {
+    for (int i = 1; i < 10; ++i) {
       ILLEGAL_WINDOWS_NAMES.add("COM" + i);
       ILLEGAL_WINDOWS_NAMES.add("LPT" + i);
     }
@@ -39,26 +51,39 @@ public class WindowsOSUtils {
 
   public static final String OS_SEGMENT_ERROR =
       String.format(
-          "In Windows System, the path shall not contains %s, equals one of 
%s, or ends with '.' or ' '.",
+          "In Windows System, the path shall not contain %s or ASCII control 
characters, equals one of %s with or without an extension, or ends with '.' or 
' '.",
           ILLEGAL_WINDOWS_CHARS, ILLEGAL_WINDOWS_NAMES);
 
   public static boolean isLegalPathSegment4Windows(final String pathSegment) {
     if (!SystemUtils.IS_OS_WINDOWS) {
       return true;
     }
-    for (final char illegalChar : ILLEGAL_WINDOWS_CHARS.toCharArray()) {
-      if (pathSegment.indexOf(illegalChar) != -1) {
-        return false;
-      }
+    if (containsIllegalWindowsChar(pathSegment)) {
+      return false;
     }
     if (pathSegment.endsWith(".") || pathSegment.endsWith(" ")) {
       return false;
     }
-    for (final String illegalName : ILLEGAL_WINDOWS_NAMES) {
-      if (pathSegment.equalsIgnoreCase(illegalName)) {
-        return false;
-      }
+    if (isIllegalWindowsName(pathSegment)) {
+      return false;
     }
     return true;
   }
+
+  private static boolean containsIllegalWindowsChar(final String pathSegment) {
+    for (int i = 0; i < pathSegment.length(); ++i) {
+      final char ch = pathSegment.charAt(i);
+      if (ch < ' ' || ILLEGAL_WINDOWS_CHARS.indexOf(ch) != -1) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private static boolean isIllegalWindowsName(final String pathSegment) {
+    final int extensionStartIndex = pathSegment.indexOf('.');
+    final String nameWithoutExtension =
+        extensionStartIndex < 0 ? pathSegment : pathSegment.substring(0, 
extensionStartIndex);
+    return 
ILLEGAL_WINDOWS_NAMES.contains(nameWithoutExtension.toUpperCase(Locale.ENGLISH));
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/FileUtilsTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/FileUtilsTest.java
index e25755f4c17..cc1586f5f74 100644
--- 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/FileUtilsTest.java
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/FileUtilsTest.java
@@ -25,6 +25,7 @@ import org.apache.tsfile.write.TsFileWriter;
 import org.apache.tsfile.write.record.Tablet;
 import org.apache.tsfile.write.schema.MeasurementSchema;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -60,6 +61,13 @@ public class FileUtilsTest {
     FileUtils.moveFileWithMD5Check(tstFile, targetDir);
   }
 
+  @Test
+  public void testGetIllegalError4DirectoryRejectsEmptyPath() {
+    Assert.assertNotNull(FileUtils.getIllegalError4Directory(null));
+    Assert.assertNotNull(FileUtils.getIllegalError4Directory(""));
+    Assert.assertNull(FileUtils.getIllegalError4Directory("valid_dir"));
+  }
+
   private void generateFile(File tsfile) throws WriteProcessException, 
IOException {
     try (TsFileWriter writer = new TsFileWriter(tsfile)) {
       writer.registerAlignedTimeseries(
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/WindowsOSUtilsTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/WindowsOSUtilsTest.java
index bbe847b6f8e..270c229e237 100644
--- 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/WindowsOSUtilsTest.java
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/WindowsOSUtilsTest.java
@@ -37,5 +37,17 @@ public class WindowsOSUtilsTest {
     Assert.assertFalse(isLegalPathSegment4Windows("C."));
     Assert.assertFalse(isLegalPathSegment4Windows("a:b<|"));
     Assert.assertFalse(isLegalPathSegment4Windows("COM1"));
+    Assert.assertFalse(isLegalPathSegment4Windows("com1"));
+    Assert.assertFalse(isLegalPathSegment4Windows("COM1.txt"));
+    Assert.assertFalse(isLegalPathSegment4Windows("NUL.log"));
+    Assert.assertFalse(isLegalPathSegment4Windows("LPT9.tmp"));
+    Assert.assertFalse(isLegalPathSegment4Windows("COM\u00B9"));
+    Assert.assertFalse(isLegalPathSegment4Windows("LPT\u00B2.log"));
+    Assert.assertFalse(isLegalPathSegment4Windows("name\tpart"));
+    Assert.assertFalse(isLegalPathSegment4Windows("name" + 
Character.toString((char) 0) + "part"));
+
+    Assert.assertTrue(isLegalPathSegment4Windows("COM0"));
+    Assert.assertTrue(isLegalPathSegment4Windows("LPT0"));
+    Assert.assertTrue(isLegalPathSegment4Windows("COM\u00B4"));
   }
 }

Reply via email to