--- old/src/share/classes/java/io/File.java 2013-05-01 17:25:02.458955666 -0700 +++ new/src/share/classes/java/io/File.java 2013-05-01 17:25:02.286955671 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, 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 @@ -156,7 +156,7 @@ private static final FileSystem fs = DefaultFileSystem.getFileSystem(); /** - * This abstract pathname's normalized pathname string. A normalized + * This abstract pathname's normalized pathname string. A normalized * pathname string uses the default name-separator character and does not * contain any duplicate or redundant separators. * @@ -165,6 +165,32 @@ private final String path; /** + * Enum type that indicates the status of a file path. + */ + private static enum PathStatus { INVALID, CHECKED }; + + /** + * The flag indicating whether the file path is invalid. + */ + private transient PathStatus status = null; + + /** + * Check if the file has an invalid path. Currently, the inspection of + * a file path is very limited, and it only covers Nul character check. + * Returning true means the path is definitely invalid/garbage. But + * returning false does not guarantee that the path is valid. + * + * @return true if the file path is invalid. + */ + final boolean isInvalid() { + if (status == null) { + status = (this.path.indexOf('\u0000') < 0 ? PathStatus.CHECKED + : PathStatus.INVALID); + } + return (status == PathStatus.INVALID); + } + + /** * The length of this abstract pathname's prefix, or zero if it has no * prefix. */ @@ -586,6 +612,9 @@ * @see Path#toRealPath */ public String getCanonicalPath() throws IOException { + if (isInvalid()) { + throw new IOException("Invalid file path"); + } return fs.canonicalize(fs.resolve(this)); } @@ -651,6 +680,9 @@ */ @Deprecated public URL toURL() throws MalformedURLException { + if (isInvalid()) { + throw new MalformedURLException("Invalid file path"); + } return new URL("file", "", slashify(getAbsolutePath(), isDirectory())); } @@ -730,6 +762,9 @@ if (security != null) { security.checkRead(path); } + if (isInvalid()) { + return false; + } return fs.checkAccess(this, FileSystem.ACCESS_READ); } @@ -755,6 +790,9 @@ if (security != null) { security.checkWrite(path); } + if (isInvalid()) { + return false; + } return fs.checkAccess(this, FileSystem.ACCESS_WRITE); } @@ -775,6 +813,9 @@ if (security != null) { security.checkRead(path); } + if (isInvalid()) { + return false; + } return ((fs.getBooleanAttributes(this) & FileSystem.BA_EXISTS) != 0); } @@ -802,6 +843,9 @@ if (security != null) { security.checkRead(path); } + if (isInvalid()) { + return false; + } return ((fs.getBooleanAttributes(this) & FileSystem.BA_DIRECTORY) != 0); } @@ -832,6 +876,9 @@ if (security != null) { security.checkRead(path); } + if (isInvalid()) { + return false; + } return ((fs.getBooleanAttributes(this) & FileSystem.BA_REGULAR) != 0); } @@ -858,6 +905,9 @@ if (security != null) { security.checkRead(path); } + if (isInvalid()) { + return false; + } return ((fs.getBooleanAttributes(this) & FileSystem.BA_HIDDEN) != 0); } @@ -887,6 +937,9 @@ if (security != null) { security.checkRead(path); } + if (isInvalid()) { + return 0L; + } return fs.getLastModifiedTime(this); } @@ -915,6 +968,9 @@ if (security != null) { security.checkRead(path); } + if (isInvalid()) { + return 0L; + } return fs.getLength(this); } @@ -950,6 +1006,9 @@ public boolean createNewFile() throws IOException { SecurityManager security = System.getSecurityManager(); if (security != null) security.checkWrite(path); + if (isInvalid()) { + throw new IOException("Invalid file path"); + } return fs.createFileExclusively(path); } @@ -976,6 +1035,9 @@ if (security != null) { security.checkDelete(path); } + if (isInvalid()) { + return false; + } return fs.delete(this); } @@ -1011,6 +1073,9 @@ if (security != null) { security.checkDelete(path); } + if (isInvalid()) { + return; + } DeleteOnExitHook.add(path); } @@ -1051,6 +1116,9 @@ if (security != null) { security.checkRead(path); } + if (isInvalid()) { + return null; + } return fs.list(this); } @@ -1242,6 +1310,9 @@ if (security != null) { security.checkWrite(path); } + if (isInvalid()) { + return false; + } return fs.createDirectory(this); } @@ -1317,6 +1388,12 @@ security.checkWrite(path); security.checkWrite(dest.path); } + if (dest == null) { + throw new NullPointerException(); + } + if (this.isInvalid() || dest.isInvalid()) { + return false; + } return fs.rename(this, dest); } @@ -1352,6 +1429,9 @@ if (security != null) { security.checkWrite(path); } + if (isInvalid()) { + return false; + } return fs.setLastModifiedTime(this, time); } @@ -1379,6 +1459,9 @@ if (security != null) { security.checkWrite(path); } + if (isInvalid()) { + return false; + } return fs.setReadOnly(this); } @@ -1419,6 +1502,9 @@ if (security != null) { security.checkWrite(path); } + if (isInvalid()) { + return false; + } return fs.setPermission(this, FileSystem.ACCESS_WRITE, writable, ownerOnly); } @@ -1493,6 +1579,9 @@ if (security != null) { security.checkWrite(path); } + if (isInvalid()) { + return false; + } return fs.setPermission(this, FileSystem.ACCESS_READ, readable, ownerOnly); } @@ -1570,6 +1659,9 @@ if (security != null) { security.checkWrite(path); } + if (isInvalid()) { + return false; + } return fs.setPermission(this, FileSystem.ACCESS_EXECUTE, executable, ownerOnly); } @@ -1629,6 +1721,9 @@ if (security != null) { security.checkExec(path); } + if (isInvalid()) { + return false; + } return fs.checkAccess(this, FileSystem.ACCESS_EXECUTE); } @@ -1705,6 +1800,9 @@ sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); sm.checkRead(path); } + if (isInvalid()) { + return 0L; + } return fs.getSpace(this, FileSystem.SPACE_TOTAL); } @@ -1721,7 +1819,7 @@ * makes no guarantee that write operations to this file system * will succeed. * - * @return The number of unallocated bytes on the partition 0L + * @return The number of unallocated bytes on the partition or 0L * if the abstract pathname does not name a partition. This * value will be less than or equal to the total file system size * returned by {@link #getTotalSpace}. @@ -1740,6 +1838,9 @@ sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); sm.checkRead(path); } + if (isInvalid()) { + return 0L; + } return fs.getSpace(this, FileSystem.SPACE_FREE); } @@ -1778,6 +1879,9 @@ sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); sm.checkRead(path); } + if (isInvalid()) { + return 0L; + } return fs.getSpace(this, FileSystem.SPACE_USABLE); } @@ -1787,8 +1891,8 @@ private TempDirectory() { } // temporary directory location - private static final File tmpdir = new File(fs.normalize(AccessController - .doPrivileged(new GetPropertyAction("java.io.tmpdir")))); + private static final File tmpdir = new File(AccessController + .doPrivileged(new GetPropertyAction("java.io.tmpdir"))); static File location() { return tmpdir; } @@ -1899,6 +2003,9 @@ throw se; } } + if (f.isInvalid()) { + throw new IOException("Unable to create temporary file"); + } } while (!fs.createFileExclusively(f.getPath())); return f; } --- old/src/share/classes/java/io/FileInputStream.java 2013-05-01 17:25:03.002955650 -0700 +++ new/src/share/classes/java/io/FileInputStream.java 2013-05-01 17:25:02.854955654 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, 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 @@ -123,6 +123,9 @@ if (name == null) { throw new NullPointerException(); } + if (file.isInvalid()) { + throw new FileNotFoundException("Invalid file path"); + } fd = new FileDescriptor(); fd.attach(this); open(name); --- old/src/share/classes/java/io/FileOutputStream.java 2013-05-01 17:25:03.494955636 -0700 +++ new/src/share/classes/java/io/FileOutputStream.java 2013-05-01 17:25:03.330955640 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, 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 @@ -196,6 +196,9 @@ if (name == null) { throw new NullPointerException(); } + if (file.isInvalid()) { + throw new FileNotFoundException("Invalid file path"); + } this.fd = new FileDescriptor(); fd.attach(this); this.append = append; --- old/src/share/classes/java/io/RandomAccessFile.java 2013-05-01 17:25:03.914955623 -0700 +++ new/src/share/classes/java/io/RandomAccessFile.java 2013-05-01 17:25:03.766955627 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, 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 @@ -228,6 +228,9 @@ if (name == null) { throw new NullPointerException(); } + if (file.isInvalid()) { + throw new FileNotFoundException("Invalid file path"); + } fd = new FileDescriptor(); fd.attach(this); open(name, imode); --- /dev/null 2013-05-01 09:27:59.347801384 -0700 +++ new/test/java/io/File/NulFile.java 2013-05-01 17:25:04.198955616 -0700 @@ -0,0 +1,625 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8003992 + * @summary Test a file whose path name is embedded with NUL character, and + * ensure it is handled correctly. + * @author Dan Xu + */ + +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.file.InvalidPathException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; + +public class NulFile { + + private static final char CHAR_NUL = '\u0000'; + + private static final String ExceptionMsg = "Invalid file path"; + + public static void main(String[] args) { + testFile(); + testFileInUnix(); + testFileInWindows(); + testTempFile(); + } + + private static void testFile() { + test(new File(new StringBuilder().append(CHAR_NUL).toString())); + test(new File( + new StringBuilder().append("").append(CHAR_NUL).toString())); + test(new File( + new StringBuilder().append(CHAR_NUL).append("").toString())); + } + + private static void testFileInUnix() { + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) + return; + + String unixFile = "/"; + test(unixFile); + + unixFile = "//"; + test(unixFile); + + unixFile = "data/info"; + test(unixFile); + + unixFile = "/data/info"; + test(unixFile); + + unixFile = "//data//info"; + test(unixFile); + } + + private static void testFileInWindows() { + String osName = System.getProperty("os.name"); + if (!osName.startsWith("Windows")) + return; + + String windowsFile = "\\"; + test(windowsFile); + + windowsFile = "\\\\"; + test(windowsFile); + + windowsFile = "/"; + test(windowsFile); + + windowsFile = "//"; + test(windowsFile); + + windowsFile = "/\\"; + test(windowsFile); + + windowsFile = "\\/"; + test(windowsFile); + + windowsFile = "data\\info"; + test(windowsFile); + + windowsFile = "\\data\\info"; + test(windowsFile); + + windowsFile = "\\\\server\\data\\info"; + test(windowsFile); + + windowsFile = "z:data\\info"; + test(windowsFile); + + windowsFile = "z:\\data\\info"; + test(windowsFile); + } + + private static void test(final String name) { + int length = name.length(); + + for (int i = 0; i <= length; i++) { + StringBuilder sbName = new StringBuilder(name); + sbName.insert(i, CHAR_NUL); + String curName = sbName.toString(); + + // test File(String parent, String child) + File testFile = new File(curName, "child"); + test(testFile); + testFile = new File("parent", curName); + test(testFile); + + // test File(String pathname) + testFile = new File(curName); + test(testFile); + + // test File(File parent, String child) + testFile = new File(new File(curName), "child"); + test(testFile); + testFile = new File(new File("parent"), curName); + test(testFile); + + // test FileInputStream + testFileInputStream(curName); + + // test FileOutputStream + testFileOutputStream(curName); + + // test RandomAccessFile + testRandomAccessFile(curName); + } + } + + private static void testFileInputStream(final String str) { + boolean exceptionThrown = false; + FileInputStream is = null; + try { + is = new FileInputStream(str); + } catch (FileNotFoundException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("FileInputStream constructor" + + " should throw FileNotFoundException"); + } + if (is != null) { + throw new RuntimeException("FileInputStream constructor" + + " should fail"); + } + + exceptionThrown = false; + is = null; + try { + is = new FileInputStream(new File(str)); + } catch (FileNotFoundException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("FileInputStream constructor" + + " should throw FileNotFoundException"); + } + if (is != null) { + throw new RuntimeException("FileInputStream constructor" + + " should fail"); + } + } + + private static void testFileOutputStream(final String str) { + boolean exceptionThrown = false; + FileOutputStream os = null; + try { + os = new FileOutputStream(str); + } catch (FileNotFoundException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("FileOutputStream constructor" + + " should throw FileNotFoundException"); + } + if (os != null) { + throw new RuntimeException("FileOutputStream constructor" + + " should fail"); + } + + exceptionThrown = false; + os = null; + try { + os = new FileOutputStream(new File(str)); + } catch (FileNotFoundException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("FileOutputStream constructor" + + " should throw FileNotFoundException"); + } + if (os != null) { + throw new RuntimeException("FileOutputStream constructor" + + " should fail"); + } + } + + private static void testRandomAccessFile(final String str) { + boolean exceptionThrown = false; + RandomAccessFile raf = null; + String[] modes = {"r", "rw", "rws", "rwd"}; + + for (String mode : modes) { + try { + raf = new RandomAccessFile(str, mode); + } catch (FileNotFoundException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("RandomAccessFile constructor" + + " should throw FileNotFoundException"); + } + if (raf != null) { + throw new RuntimeException("RandomAccessFile constructor" + + " should fail"); + } + + exceptionThrown = false; + raf = null; + try { + raf = new RandomAccessFile(new File(str), mode); + } catch (FileNotFoundException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("RandomAccessFile constructor" + + " should throw FileNotFoundException"); + } + if (raf != null) { + throw new RuntimeException("RandomAccessFile constructor" + + " should fail"); + } + } + } + + private static void test(File testFile) { + test(testFile, false); + // test serialization + testSerialization(testFile); + } + + @SuppressWarnings("deprecation") + private static void test(File testFile, boolean derived) { + boolean exceptionThrown = false; + + if (testFile == null) { + throw new RuntimeException("test file should not be null."); + } + + // getPath() + if (testFile.getPath().indexOf(CHAR_NUL) < 0) { + throw new RuntimeException( + "File path should contain Nul character"); + } + // getAbsolutePath() + if (testFile.getAbsolutePath().indexOf(CHAR_NUL) < 0) { + throw new RuntimeException( + "File absolute path should contain Nul character"); + } + // getAbsoluteFile() + File derivedAbsFile = testFile.getAbsoluteFile(); + if (derived) { + if (derivedAbsFile.getPath().indexOf(CHAR_NUL) < 0) { + throw new RuntimeException( + "Derived file path should also contain Nul character"); + } + } else { + test(derivedAbsFile, true); + } + // getCanonicalPath() + try { + exceptionThrown = false; + testFile.getCanonicalPath(); + } catch (IOException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException( + "getCanonicalPath() should throw IOException with" + + " message \"" + ExceptionMsg + "\""); + } + // getCanonicalFile() + try { + exceptionThrown = false; + testFile.getCanonicalFile(); + } catch (IOException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException( + "getCanonicalFile() should throw IOException with" + + " message \"" + ExceptionMsg + "\""); + } + // toURL() + try { + exceptionThrown = false; + testFile.toURL(); + } catch (MalformedURLException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("toURL() should throw IOException with" + + " message \"" + ExceptionMsg + "\""); + } + // canRead() + if (testFile.canRead()) + throw new RuntimeException("File should not be readable"); + // canWrite() + if (testFile.canWrite()) + throw new RuntimeException("File should not be writable"); + // exists() + if (testFile.exists()) + throw new RuntimeException("File should not be existed"); + // isDirectory() + if (testFile.isDirectory()) + throw new RuntimeException("File should not be a directory"); + // isFile() + if (testFile.isFile()) + throw new RuntimeException("File should not be a file"); + // isHidden() + if (testFile.isHidden()) + throw new RuntimeException("File should not be hidden"); + // lastModified() + if (testFile.lastModified() != 0L) + throw new RuntimeException("File last modified time should be 0L"); + // length() + if (testFile.length() != 0L) + throw new RuntimeException("File length should be 0L"); + // createNewFile() + try { + exceptionThrown = false; + testFile.createNewFile(); + } catch (IOException ex) { + if (ExceptionMsg.equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException( + "createNewFile() should throw IOException with" + + " message \"" + ExceptionMsg + "\""); + } + // delete() + if (testFile.delete()) + throw new RuntimeException("Delete operation should fail"); + // list() + if (testFile.list() != null) + throw new RuntimeException("File list() should return null"); + // list(FilenameFilter) + FilenameFilter fnFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return false; + } + }; + if (testFile.list(fnFilter) != null) { + throw new RuntimeException("File list(FilenameFilter) should" + + " return null"); + } + // listFiles() + if (testFile.listFiles() != null) + throw new RuntimeException("File listFiles() should return null"); + // listFiles(FilenameFilter) + if (testFile.listFiles(fnFilter) != null) { + throw new RuntimeException("File listFiles(FilenameFilter)" + + " should return null"); + } + // listFiles(FileFilter) + FileFilter fFilter = new FileFilter() { + @Override + public boolean accept(File file) { + return false; + } + }; + if (testFile.listFiles(fFilter) != null) { + throw new RuntimeException("File listFiles(FileFilter)" + + " should return null"); + } + // mkdir() + if (testFile.mkdir()) { + throw new RuntimeException("File should not be able to" + + " create directory"); + } + // mkdirs() + if (testFile.mkdirs()) { + throw new RuntimeException("File should not be able to" + + " create directories"); + } + // renameTo(File) + if (testFile.renameTo(new File("dest"))) + throw new RuntimeException("File rename should fail"); + if (new File("dest").renameTo(testFile)) + throw new RuntimeException("File rename should fail"); + try { + exceptionThrown = false; + testFile.renameTo(null); + } catch (NullPointerException ex) { + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("File rename should thrown NPE"); + } + // setLastModified(long) + if (testFile.setLastModified(0L)) { + throw new RuntimeException("File should fail to set" + + " last modified time"); + } + try { + exceptionThrown = false; + testFile.setLastModified(-1); + } catch (IllegalArgumentException ex) { + if ("Negative time".equals(ex.getMessage())) + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("File should fail to set" + + " last modified time with message \"Negative time\""); + } + // setReadOnly() + if (testFile.setReadOnly()) + throw new RuntimeException("File should fail to set read-only"); + // setWritable(boolean writable, boolean ownerOnly) + if (testFile.setWritable(true, true)) + throw new RuntimeException("File should fail to set writable"); + if (testFile.setWritable(true, false)) + throw new RuntimeException("File should fail to set writable"); + if (testFile.setWritable(false, true)) + throw new RuntimeException("File should fail to set writable"); + if (testFile.setWritable(false, false)) + throw new RuntimeException("File should fail to set writable"); + // setWritable(boolean writable) + if (testFile.setWritable(false)) + throw new RuntimeException("File should fail to set writable"); + if (testFile.setWritable(true)) + throw new RuntimeException("File should fail to set writable"); + // setReadable(boolean readable, boolean ownerOnly) + if (testFile.setReadable(true, true)) + throw new RuntimeException("File should fail to set readable"); + if (testFile.setReadable(true, false)) + throw new RuntimeException("File should fail to set readable"); + if (testFile.setReadable(false, true)) + throw new RuntimeException("File should fail to set readable"); + if (testFile.setReadable(false, false)) + throw new RuntimeException("File should fail to set readable"); + // setReadable(boolean readable) + if (testFile.setReadable(false)) + throw new RuntimeException("File should fail to set readable"); + if (testFile.setReadable(true)) + throw new RuntimeException("File should fail to set readable"); + // setExecutable(boolean executable, boolean ownerOnly) + if (testFile.setExecutable(true, true)) + throw new RuntimeException("File should fail to set executable"); + if (testFile.setExecutable(true, false)) + throw new RuntimeException("File should fail to set executable"); + if (testFile.setExecutable(false, true)) + throw new RuntimeException("File should fail to set executable"); + if (testFile.setExecutable(false, false)) + throw new RuntimeException("File should fail to set executable"); + // setExecutable(boolean executable) + if (testFile.setExecutable(false)) + throw new RuntimeException("File should fail to set executable"); + if (testFile.setExecutable(true)) + throw new RuntimeException("File should fail to set executable"); + // canExecute() + if (testFile.canExecute()) + throw new RuntimeException("File should not be executable"); + // getTotalSpace() + if (testFile.getTotalSpace() != 0L) + throw new RuntimeException("The total space should be 0L"); + // getFreeSpace() + if (testFile.getFreeSpace() != 0L) + throw new RuntimeException("The free space should be 0L"); + // getUsableSpace() + if (testFile.getUsableSpace() != 0L) + throw new RuntimeException("The usable space should be 0L"); + // compareTo(File null) + try { + exceptionThrown = false; + testFile.compareTo(null); + } catch (NullPointerException ex) { + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("compareTo(null) should throw NPE"); + } + // toString() + if (testFile.toString().indexOf(CHAR_NUL) < 0) { + throw new RuntimeException( + "File path should contain Nul character"); + } + // toPath() + try { + exceptionThrown = false; + testFile.toPath(); + } catch (InvalidPathException ex) { + exceptionThrown = true; + } + if (!exceptionThrown) { + throw new RuntimeException("toPath() should throw" + + " InvalidPathException"); + } + } + + private static void testSerialization(File testFile) { + String path = testFile.getPath(); + try { + // serialize test file + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(testFile); + oos.close(); + // deserialize test file + byte[] bytes = baos.toByteArray(); + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(is); + File newFile = (File) ois.readObject(); + // test + String newPath = newFile.getPath(); + if (!path.equals(newPath)) { + throw new RuntimeException( + "Serialization should not change file path"); + } + test(newFile, false); + } catch (IOException | ClassNotFoundException ex) { + System.err.println("Exception happens in testSerialization"); + System.err.println(ex.getMessage()); + } + } + + private static void testTempFile() { + final String[] names = {"x", "xx", "xxx", "xxxx"}; + final String shortPrefix = "sp"; + final String prefix = "prefix"; + final String suffix = "suffix"; + File tmpDir = new File("tmpDir"); + + for (String name : names) { + int length = name.length(); + for (int i = 0; i <= length; i++) { + StringBuilder sbName = new StringBuilder(name); + sbName.insert(i, CHAR_NUL); + String curName = sbName.toString(); + + // test prefix + testCreateTempFile(curName, suffix, tmpDir); + // test suffix + testCreateTempFile(shortPrefix, curName, tmpDir); + testCreateTempFile(prefix, curName, tmpDir); + // test directory + testCreateTempFile(shortPrefix, suffix, new File(curName)); + testCreateTempFile(prefix, suffix, new File(curName)); + } + } + } + + private static void testCreateTempFile(String prefix, String suffix, + File directory) { + // createTempFile(String prefix, String suffix, File directory) + boolean exceptionThrown = false; + boolean shortPrefix = (prefix.length() < 3); + if (shortPrefix) { + try { + File.createTempFile(prefix, suffix, directory); + } catch (IllegalArgumentException ex) { + if ("Prefix string too short".equals(ex.getMessage())) + exceptionThrown = true; + } catch (IOException ioe) { + System.err.println("IOException happens in testCreateTempFile"); + System.err.println(ioe.getMessage()); + } + } else { + try { + File.createTempFile(prefix, suffix, directory); + } catch (IOException ex) { + if ("Unable to create temporary file".equals(ex.getMessage())) + exceptionThrown = true; + } + } + if (!exceptionThrown) { + throw new RuntimeException("createTempFile() should throw" + + (shortPrefix ? " IllegalArgumentException" + : " IOException")); + } + } +}