diff --git a/core/src/main/java/hudson/util/jna/Kernel32Utils.java b/core/src/main/java/hudson/util/jna/Kernel32Utils.java index 954b90e561ecf4c396ba68faeb261786f46bfdba..6c42ca58b0dca8e5ad3da55e419eb6ac455cc027 100644 --- a/core/src/main/java/hudson/util/jna/Kernel32Utils.java +++ b/core/src/main/java/hudson/util/jna/Kernel32Utils.java @@ -58,7 +58,22 @@ public class Kernel32Utils { } public static int getWin32FileAttributes(File file) throws IOException { - return Kernel32.INSTANCE.GetFileAttributesW(new WString(file.getCanonicalPath())); + // allow lookup of paths longer than MAX_PATH + // http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx + String canonicalPath = file.getCanonicalPath(); + String path = null; + if(canonicalPath.length() < 260) { + // path is short, use as-is + path = canonicalPath; + } else if(canonicalPath.startsWith("\\\\")) { + // network share + // \\server\share --> \\?\UNC\server\share + path = "\\\\?\\UNC\\" + canonicalPath.substring(2); + } else { + // prefix, canonical path should be normalized and absolute so this should work. + path = "\\\\?\\" + canonicalPath; + } + return Kernel32.INSTANCE.GetFileAttributesW(new WString(path)); } public static boolean isJunctionOrSymlink(File file) throws IOException { diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index 4d2a9fab23423f3dfccbe2b7226b98c78a2c7968..eb04e6d36485a5e9236cdc2276e765b963a2feac 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -474,5 +474,32 @@ public class FilePathTest extends ChannelTestCase { Util.deleteRecursive(tmp); } } - + + @Bug(15418) + public void testDeleteLongPathOnWindows() throws Exception { + File tmp = Util.createTempDir(); + try { + FilePath d = new FilePath(french, tmp.getPath()); + + // construct a very long path + StringBuilder sb = new StringBuilder(); + while(sb.length() + tmp.getPath().length() < 260 - "very/".length()) { + sb.append("very/"); + } + sb.append("pivot/very/very/long/path"); + + FilePath longPath = d.child(sb.toString()); + longPath.mkdirs(); + FilePath childInLongPath = longPath.child("file.txt"); + childInLongPath.touch(0); + + File firstDirectory = new File(tmp.getAbsolutePath() + "/very"); + Util.deleteRecursive(firstDirectory); + + assertFalse("Could not delete directory!", firstDirectory.exists()); + + } finally { + Util.deleteRecursive(tmp); + } + } }