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"));
}
}