8383867: File.getCanonicalPath drops backslash from UNC path with directory junctions

Reviewed-by: alanb
This commit is contained in:
Roman Marchenko 2026-06-02 14:54:16 +00:00 committed by Alan Bateman
parent cb502e7993
commit c469bb2cd7
2 changed files with 33 additions and 11 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2026, 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
@ -181,10 +181,12 @@ WCHAR* getFinalPath(WCHAR* path, WCHAR* finalPath, DWORD size)
int isUnc = (finalPath[4] == L'U' &&
finalPath[5] == L'N' &&
finalPath[6] == L'C');
// keep leading double backslashes in case of UNC
const int startIdx = (isUnc) ? 1 : 0;
int prefixLen = (isUnc) ? 7 : 4;
// the amount to copy includes terminator
int amountToCopy = len - prefixLen + 1;
wmemmove(finalPath, finalPath + prefixLen, amountToCopy);
wmemmove(finalPath + startIdx, finalPath + prefixLen, amountToCopy);
}
return finalPath;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2026, 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
@ -22,7 +22,7 @@
*/
/* @test
* @bug 4899022 8003887 8355342
* @bug 4899022 8003887 8355342 8383867
* @summary Look for erroneous representation of drive letter
* @run junit GetCanonicalPath
*/
@ -148,7 +148,14 @@ public class GetCanonicalPath {
Runtime rt = Runtime.getRuntime();
String share =
"\\\\localhost\\" + cwd.charAt(0) + "$" + cwd.substring(2);
String junctionName = "tmpDir";
try {
// create directory junction
Path tmpDir = Files.createTempDirectory(junctionName);
String tmpDirLink = cwd + "\\" + junctionName;
Process pmklink = rt.exec(new String[] {"cmd", "/c", "mklink", "/J", tmpDirLink, tmpDir.toString()});
assertEquals(0, pmklink.waitFor());
Process p = rt.exec(new String[] {"net", "use", drive + ":", share});
assertEquals(0, p.waitFor());
} catch (InterruptedException x) {
@ -157,13 +164,26 @@ public class GetCanonicalPath {
// check that the canonical path name and its content are as expected
try {
final String filename = "file.txt";
final String text = "This is some text";
Files.writeString(Path.of(share, filename), text);
File file = new File(drive + ":\\" + filename);
String canonicalPath = file.getCanonicalPath();
assertEquals(drive + ":\\" + filename, canonicalPath);
assertEquals(text, Files.readString(Path.of(canonicalPath)));
// use drive letter
{
final String filename = "file.txt";
final String text = "This is some text";
Files.writeString(Path.of(share, filename), text);
File file = new File(drive + ":\\" + filename);
String canonicalPath = file.getCanonicalPath();
assertEquals(drive + ":\\" + filename, canonicalPath);
assertEquals(text, Files.readString(Path.of(canonicalPath)));
}
// use reparse point (directory junction)
{
final String filename = junctionName + "\\file.txt";
final String text = "This is some text";
Files.writeString(Path.of(share, filename), text);
File file = new File(drive + ":\\" + filename);
String canonicalPath = file.getCanonicalPath();
assertTrue(canonicalPath.startsWith("\\\\localhost\\"));
assertEquals(text, Files.readString(Path.of(canonicalPath)));
}
} finally {
try {
Process p = rt.exec(new String[] {"net", "use", drive + ":", "/Delete"});