diff --git a/src/java.base/unix/native/libjava/path_util.c b/src/java.base/unix/native/libjava/path_util.c index 1f2cdc46f0c..e75bf6bc90c 100644 --- a/src/java.base/unix/native/libjava/path_util.c +++ b/src/java.base/unix/native/libjava/path_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,7 +157,13 @@ collapse(char *path) for (j = i - 1; j >= 0; j--) { if (ix[j]) break; } - if (j < 0) continue; + if (j < 0) { + // If there is no preceding name and this path is absolute, + // then remove this instance of ".." + if (path[0] == '/') + ix[i] = 0; + continue; + } ix[j] = 0; ix[i] = 0; } diff --git a/test/jdk/java/io/File/GetCanonicalPath.java b/test/jdk/java/io/File/GetCanonicalPath.java index 0abf25244d2..e54227e44b4 100644 --- a/test/jdk/java/io/File/GetCanonicalPath.java +++ b/test/jdk/java/io/File/GetCanonicalPath.java @@ -23,7 +23,6 @@ /* @test * @bug 4899022 - * @requires (os.family == "windows") * @summary Look for erroneous representation of drive letter * @run junit GetCanonicalPath */ @@ -35,6 +34,8 @@ import java.util.List; import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -43,7 +44,7 @@ import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; public class GetCanonicalPath { - private static Stream pathProvider() { + private static Stream pathProviderWindows() { List list = new ArrayList(); File dir = new File(System.getProperty("user.dir", ".")); @@ -80,21 +81,43 @@ public class GetCanonicalPath { return list.stream(); } + private static Stream pathProviderUnix() { + return Stream.of( + Arguments.of("/../../../../../a/b/c", "/a/b/c"), + Arguments.of("/../../../../../a/../b/c", "/b/c"), + Arguments.of("/../../../../../a/../../b/c", "/b/c"), + Arguments.of("/../../../../../a/../../../b/c", "/b/c"), + Arguments.of("/../../../../../a/../../../../b/c", "/b/c") + ); + } + @ParameterizedTest + @EnabledOnOs({OS.AIX, OS.LINUX, OS.MAC}) + @MethodSource("pathProviderUnix") + void goodPathsUnix(String pathname, String expected) throws IOException { + File file = new File(pathname); + String canonicalPath = file.getCanonicalPath(); + assertEquals(expected, canonicalPath); + } + + @ParameterizedTest + @EnabledOnOs(OS.WINDOWS) @ValueSource(strings = {"\\\\?", "\\\\?\\UNC", "\\\\?\\UNC\\"}) - void badPaths(String pathname) { + void badPathsWindows(String pathname) { assertThrows(IOException.class, () -> new File(pathname).getCanonicalPath()); } @ParameterizedTest - @MethodSource("pathProvider") - void goodPaths(String pathname, String expected) throws IOException { + @EnabledOnOs(OS.WINDOWS) + @MethodSource("pathProviderWindows") + void goodPathsWindows(String pathname, String expected) throws IOException { File file = new File(pathname); String canonicalPath = file.getCanonicalPath(); assertEquals(expected, canonicalPath); } @Test + @EnabledOnOs(OS.WINDOWS) void driveLetter() throws IOException { String path = new File("c:/").getCanonicalPath(); assertFalse(path.length() > 3, "Drive letter incorrectly represented");