When a null is encountered in a filename in java.io.File
, that character and all characters after it are ignored, resulting in some strange behavior in File.exists()
.
Is this behavior some aspect of java.io.File.exists()
that I've missed?
Example:
package os;
import java.io.File;
import java.io.IOException;
public class FileNullCheck
{
public static void main(String[] args)
{
File tmp = new File("a.txt");
try
{
tmp.createNewFile();
}
catch (IOException e)
{
e.printStackTrace();
return;
}
String a = "a.txt";
System.out.printf("a.txt exists: %b (len=%d)%n",new File(a).exists(),a.length());
String anull = new String(new byte[] { 'a', '.', 't', 'x', 't', 0x00 });
System.out.printf("a.txt (null) exists: %b (len=%d)%n",new File(anull).exists(),anull.length());
String anullx = new String(new byte[] { 'a', '.', 't', 'x', 't', 0x00, 'x' });
System.out.printf("a.txt (nullx) exists: %b (len=%d)%n",new File(anullx).exists(),anullx.length());
}
}
The results of running this.
a.txt exists: true (len=5) a.txt (null) exists: true (len=6) a.txt (nullx) exists: true (len=7)
The Linux system has the following JVM.
Java(TM) SE Runtime Environment (build 1.7.0_10-b18) Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode)
The behavior seems to be C-like and the string used to validate the file on the filesystem is truncated at the null.
But I would expect the behavior at Java to return false for File.exists()
on these invalid filenames.
Update: Sep 19, 2013
Java 1.7.0 update 40 has fixed this as part of bug JDK-8014846 : File and other classes in java.io do not handle embedded nulls properly
On RHEL it appears that the nul byte terminates the file name (as you might expect in C)
System.out.println("a exists " + new File("a").exists());
FileOutputStream fos = new FileOutputStream(new File("a\u0000aa"));
fos.close();
System.out.println("a exists " + new File("a").exists());
prints
a exists false
a exists true
I suspect Java should prevent you from attempting to use a file name with a nul byte.
If using JDK 1.7+ the java.nio.files.Paths.get(URI) can be used to test for Nul (it seems)
A modification to the original tests produces a useful Exception
package os;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileNullCheck
{
public static void main(String[] args) throws Exception
{
File tmp = new File("a.txt");
try
{
tmp.createNewFile();
}
catch (IOException e)
{
e.printStackTrace();
return;
}
String a = "a.txt";
testExists("a.txt", a);
String anull = new String(new byte[] { 'a', '.', 't', 'x', 't', 0x00 }, "UTF-8");
testExists("a.txt (null)", anull);
String anullx = new String(new byte[] { 'a', '.', 't', 'x', 't', 0x00, 'x' }, "UTF-8");
testExists("a.txt (nullx)", anullx);
}
private static void testExists(String label, String filename) throws IOException
{
File file = new File(filename);
System.out.printf("%s exists: %b%n", label, file.exists());
System.out.printf(" filename.length = %d%n", filename.length());
Path path = Paths.get(file.toURI());
boolean symlink = Files.isSymbolicLink(path);
System.out.printf(" nio issymlink = %b%n",symlink);
}
}
Results in the output
a.txt exists: true filename.length = 5 nio issymlink = false a.txt (null) exists: true filename.length = 6 Exception in thread "main" java.nio.file.InvalidPathException: Nul character not allowed: /home/joakim/code/Stackoverflow/a.txt at sun.nio.fs.UnixPath.checkNotNul(UnixPath.java:93) at sun.nio.fs.UnixPath.normalizeAndCheck(UnixPath.java:83) at sun.nio.fs.UnixPath.(UnixPath.java:71) at sun.nio.fs.UnixFileSystem.getPath(UnixFileSystem.java:281) at java.io.File.toPath(File.java:2069) at sun.nio.fs.UnixUriUtils.fromUri(UnixUriUtils.java:61) at sun.nio.fs.UnixFileSystemProvider.getPath(UnixFileSystemProvider.java:97) at java.nio.file.Paths.get(Paths.java:138) at os.FileNullCheck.testExists(FileNullCheck.java:39) at os.FileNullCheck.main(FileNullCheck.java:28)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With