A DESCRIPTION OF THE PROBLEM :
There's a bug in the Windows NIO FS implementation revealed by the attached test case. The cause is inconsistent handling of MAX_PATH limits. Windows treats extended attributes as just any other kind of file with a ":ea-name" suffix. When a path is just under the MAX_PATH length, adding the name of the extended attribute can push it over the limit, which would require a magic \\?\ prefix to be added to the path. This doesn't happen, creating a small "black hole" where paths of just the wrong length can't have EAs set.
From examining the code, it tries to use short path form when possible (WindowsPath.java:178). It isn't clear to me why the code tries to do this. There don't seem to be any advantages to using the non \\?\ prefixed form, implying the code could be simplified by always using the long-capable form.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile and run attached test case on a Windows system.
2. Observe that an exception is thrown for the long EA name but not for the short EA name.
3. Play with the value of "padding" to see that the issue goes away if the path length is adjusted.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No exception.
ACTUAL -
Exception in thread "main" java.nio.file.NoSuchFileException: C:\scratch\ea-length-bug\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:reallyquitelonglongattrname
at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:85)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:96)
at java.base/sun.nio.fs.WindowsUserDefinedFileAttributeView.write(WindowsUserDefinedFileAttributeView.java:202)
at java.base/sun.nio.fs.AbstractUserDefinedFileAttributeView.setAttribute(AbstractUserDefinedFileAttributeView.java:72)
at java.base/sun.nio.fs.AbstractFileSystemProvider.setAttribute(AbstractFileSystemProvider.java:81)
at java.base/java.nio.file.Files.setAttribute(Files.java:1911)
at software.hydraulic.ExtendedAttributeLengthBugTest.setEA(ExtendedAttributeLengthBugTest.java:39)
at software.hydraulic.ExtendedAttributeLengthBugTest.main(ExtendedAttributeLengthBugTest.java:27)
---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class ExtendedAttributeLengthBugTest {
public static void main(String[] args) throws IOException {
// Somewhere we can try out the bug.
var tmp = Files.createDirectory(Path.of("ea-length-bug")).toAbsolutePath();
try {
// Temp directory adds some characters.
var len = tmp.toString().length();
// We need to run up to MAX_PATH for directories, but not quite go over it.
var MAX_PATH = 247;
var requiredLen = MAX_PATH - len - 2;
// Create a really long directory name.
Path longPath = tmp.resolve("x".repeat(requiredLen));
// Make sure the directory exists.
Files.createDirectory(longPath);
// Try to set an extended attribute on it.
try {
setEA(longPath, "user:short");
setEA(longPath, "user:reallyquitelonglongattrname");
} finally {
Files.delete(longPath);
}
// Should get here but can't because the length of the EA name + the file name > MAX_PATH.
} finally {
Files.delete(tmp);
}
}
private static void setEA(Path longPath, String s) throws IOException {
System.out.println("Setting short EA '" + s + "' on path of length " + longPath.toString().length());
Files.setAttribute(longPath, s, ByteBuffer.wrap("ea-value".getBytes(StandardCharsets.UTF_8)));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There is none beyond ensuring the path length never falls into the "bad zone", but this is often infeasible when parts of the path are chosen by the user.
There's a bug in the Windows NIO FS implementation revealed by the attached test case. The cause is inconsistent handling of MAX_PATH limits. Windows treats extended attributes as just any other kind of file with a ":ea-name" suffix. When a path is just under the MAX_PATH length, adding the name of the extended attribute can push it over the limit, which would require a magic \\?\ prefix to be added to the path. This doesn't happen, creating a small "black hole" where paths of just the wrong length can't have EAs set.
From examining the code, it tries to use short path form when possible (WindowsPath.java:178). It isn't clear to me why the code tries to do this. There don't seem to be any advantages to using the non \\?\ prefixed form, implying the code could be simplified by always using the long-capable form.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile and run attached test case on a Windows system.
2. Observe that an exception is thrown for the long EA name but not for the short EA name.
3. Play with the value of "padding" to see that the issue goes away if the path length is adjusted.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No exception.
ACTUAL -
Exception in thread "main" java.nio.file.NoSuchFileException: C:\scratch\ea-length-bug\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:reallyquitelonglongattrname
at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:85)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:96)
at java.base/sun.nio.fs.WindowsUserDefinedFileAttributeView.write(WindowsUserDefinedFileAttributeView.java:202)
at java.base/sun.nio.fs.AbstractUserDefinedFileAttributeView.setAttribute(AbstractUserDefinedFileAttributeView.java:72)
at java.base/sun.nio.fs.AbstractFileSystemProvider.setAttribute(AbstractFileSystemProvider.java:81)
at java.base/java.nio.file.Files.setAttribute(Files.java:1911)
at software.hydraulic.ExtendedAttributeLengthBugTest.setEA(ExtendedAttributeLengthBugTest.java:39)
at software.hydraulic.ExtendedAttributeLengthBugTest.main(ExtendedAttributeLengthBugTest.java:27)
---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class ExtendedAttributeLengthBugTest {
public static void main(String[] args) throws IOException {
// Somewhere we can try out the bug.
var tmp = Files.createDirectory(Path.of("ea-length-bug")).toAbsolutePath();
try {
// Temp directory adds some characters.
var len = tmp.toString().length();
// We need to run up to MAX_PATH for directories, but not quite go over it.
var MAX_PATH = 247;
var requiredLen = MAX_PATH - len - 2;
// Create a really long directory name.
Path longPath = tmp.resolve("x".repeat(requiredLen));
// Make sure the directory exists.
Files.createDirectory(longPath);
// Try to set an extended attribute on it.
try {
setEA(longPath, "user:short");
setEA(longPath, "user:reallyquitelonglongattrname");
} finally {
Files.delete(longPath);
}
// Should get here but can't because the length of the EA name + the file name > MAX_PATH.
} finally {
Files.delete(tmp);
}
}
private static void setEA(Path longPath, String s) throws IOException {
System.out.println("Setting short EA '" + s + "' on path of length " + longPath.toString().length());
Files.setAttribute(longPath, s, ByteBuffer.wrap("ea-value".getBytes(StandardCharsets.UTF_8)));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There is none beyond ensuring the path length never falls into the "bad zone", but this is often infeasible when parts of the path are chosen by the user.
- relates to
-
JDK-8288088 (fs) WindowsUserDefinedFileAttributeView fails to handle attrs with control chars
-
- Open
-
-
JDK-8276661 (fs) UserDefinedFileAttributeView no longer works with long path (win)
-
- Closed
-