diff --git a/make/java/java/FILES_java.gmk b/make/java/java/FILES_java.gmk index 47179069c1752ca697f722f072598a1e8a104c8b..fdd4b5519125df5ae1570dc7c269f8286697f416 100644 --- a/make/java/java/FILES_java.gmk +++ b/make/java/java/FILES_java.gmk @@ -443,7 +443,6 @@ JAVA_JAVA_java = \ java/io/FileReader.java \ java/io/PipedReader.java \ java/io/StringReader.java \ - java/io/TempFileHelper.java \ java/io/Writer.java \ java/io/BufferedWriter.java \ java/io/PrintWriter.java \ diff --git a/make/java/nio/FILES_java.gmk b/make/java/nio/FILES_java.gmk index cb416fe093263dc271018cf68d819b21adb91de4..9fbeafb48a3a4a2de217195b48b712ea1c07c298 100644 --- a/make/java/nio/FILES_java.gmk +++ b/make/java/nio/FILES_java.gmk @@ -81,12 +81,12 @@ FILES_src = \ java/nio/file/ClosedDirectoryStreamException.java \ java/nio/file/ClosedFileSystemException.java \ java/nio/file/ClosedWatchServiceException.java \ + java/nio/file/CopyMoveHelper.java \ java/nio/file/CopyOption.java \ java/nio/file/DirectoryIteratorException.java \ java/nio/file/DirectoryNotEmptyException.java \ java/nio/file/DirectoryStream.java \ java/nio/file/FileAlreadyExistsException.java \ - java/nio/file/FileRef.java \ java/nio/file/FileStore.java \ java/nio/file/FileSystem.java \ java/nio/file/FileSystemAlreadyExistsException.java \ @@ -116,6 +116,7 @@ FILES_src = \ java/nio/file/StandardCopyOption.java \ java/nio/file/StandardOpenOption.java \ java/nio/file/StandardWatchEventKind.java \ + java/nio/file/TempFileHelper.java \ java/nio/file/WatchEvent.java \ java/nio/file/WatchKey.java \ java/nio/file/WatchService.java \ @@ -127,7 +128,6 @@ FILES_src = \ java/nio/file/attribute/AclEntryType.java \ java/nio/file/attribute/AclFileAttributeView.java \ java/nio/file/attribute/AttributeView.java \ - java/nio/file/attribute/Attributes.java \ java/nio/file/attribute/BasicFileAttributeView.java \ java/nio/file/attribute/BasicFileAttributes.java \ java/nio/file/attribute/DosFileAttributeView.java \ @@ -136,8 +136,6 @@ FILES_src = \ java/nio/file/attribute/FileAttributeView.java \ java/nio/file/attribute/FileOwnerAttributeView.java \ java/nio/file/attribute/FileStoreAttributeView.java \ - java/nio/file/attribute/FileStoreSpaceAttributeView.java \ - java/nio/file/attribute/FileStoreSpaceAttributes.java \ java/nio/file/attribute/FileTime.java \ java/nio/file/attribute/GroupPrincipal.java \ java/nio/file/attribute/UserDefinedFileAttributeView.java \ @@ -246,6 +244,7 @@ FILES_src = \ sun/nio/fs/AbstractAclFileAttributeView.java \ sun/nio/fs/AbstractBasicFileAttributeView.java \ sun/nio/fs/AbstractFileTypeDetector.java \ + sun/nio/fs/AbstractFileSystemProvider.java \ sun/nio/fs/AbstractPath.java \ sun/nio/fs/AbstractPoller.java \ sun/nio/fs/AbstractUserDefinedFileAttributeView.java \ diff --git a/make/mkdemo/Makefile b/make/mkdemo/Makefile index 1e1739467cc8e0f383fcee487c72e35770a6df0a..bb29498d5a746ec785b1568b7db092387c1ec10f 100644 --- a/make/mkdemo/Makefile +++ b/make/mkdemo/Makefile @@ -31,7 +31,7 @@ BUILDDIR = .. PRODUCT = demos include $(BUILDDIR)/common/Defs.gmk -SUBDIRS = jni nio +SUBDIRS = jni SUBDIRS_desktop = applets jfc SUBDIRS_management = management SUBDIRS_misc = scripting diff --git a/src/share/classes/java/io/BufferedReader.java b/src/share/classes/java/io/BufferedReader.java index b12eaa0d0b550eb958c18142dde2e5b65f998620..e8583e046f07c1d490797c6b385026e900be9129 100644 --- a/src/share/classes/java/io/BufferedReader.java +++ b/src/share/classes/java/io/BufferedReader.java @@ -54,6 +54,7 @@ package java.io; * * @see FileReader * @see InputStreamReader + * @see java.nio.file.Files#newBufferedReader * * @author Mark Reinhold * @since JDK1.1 @@ -374,6 +375,8 @@ public class BufferedReader extends Reader { * stream has been reached * * @exception IOException If an I/O error occurs + * + * @see java.nio.file.Files#readAllLines */ public String readLine() throws IOException { return readLine(false); diff --git a/src/share/classes/java/io/BufferedWriter.java b/src/share/classes/java/io/BufferedWriter.java index 457c73f512d9eab835656046f82a00fd354f8098..4322683d367d270f975efddc897d952a75595e42 100644 --- a/src/share/classes/java/io/BufferedWriter.java +++ b/src/share/classes/java/io/BufferedWriter.java @@ -57,6 +57,7 @@ package java.io; * @see PrintWriter * @see FileWriter * @see OutputStreamWriter + * @see java.nio.file.Files#newBufferedWriter * * @author Mark Reinhold * @since JDK1.1 diff --git a/src/share/classes/java/io/File.java b/src/share/classes/java/io/File.java index 1ff3e936bae6bdc4662e415c76f9af18bc6f8bba..cde70d0b977019b77b32350b2129509b73dbe1de 100644 --- a/src/share/classes/java/io/File.java +++ b/src/share/classes/java/io/File.java @@ -35,8 +35,7 @@ import java.util.ArrayList; import java.security.AccessController; import java.security.SecureRandom; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.FileAttribute; +import java.nio.file.FileSystems; import sun.security.action.GetPropertyAction; /** @@ -139,9 +138,10 @@ import sun.security.action.GetPropertyAction; * many of the limitations of the {@code java.io.File} class. * The {@link #toPath toPath} method may be used to obtain a {@link * Path} that uses the abstract path represented by a {@code File} object to - * locate a file. The resulting {@code Path} provides more efficient and - * extensive access to file attributes, additional file operations, and I/O - * exceptions to help diagnose errors when an operation on a file fails. + * locate a file. The resulting {@code Path} may be used with the {@link + * java.nio.file.Files} class to provide more efficient and extensive access to + * additional file operations, file attributes, and I/O exceptions to help + * diagnose errors when an operation on a file fails. * * @author unascribed * @since JDK1.0 @@ -778,6 +778,12 @@ public class File * Tests whether the file denoted by this abstract pathname is a * directory. * + *

Where it is required to distinguish an I/O exception from the case + * that the file is not a directory, or where several attributes of the + * same file are required at the same time, then the {@link + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) + * Files.readAttributes} method may be used. + * * @return true if and only if the file denoted by this * abstract pathname exists and is a directory; * false otherwise @@ -786,8 +792,6 @@ public class File * If a security manager exists and its {@link * java.lang.SecurityManager#checkRead(java.lang.String)} * method denies read access to the file - * - * @see java.nio.file.attribute.Attributes#readBasicFileAttributes */ public boolean isDirectory() { SecurityManager security = System.getSecurityManager(); @@ -804,6 +808,12 @@ public class File * addition, satisfies other system-dependent criteria. Any non-directory * file created by a Java application is guaranteed to be a normal file. * + *

Where it is required to distinguish an I/O exception from the case + * that the file is not a normal file, or where several attributes of the + * same file are required at the same time, then the {@link + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) + * Files.readAttributes} method may be used. + * * @return true if and only if the file denoted by this * abstract pathname exists and is a normal file; * false otherwise @@ -812,8 +822,6 @@ public class File * If a security manager exists and its {@link * java.lang.SecurityManager#checkRead(java.lang.String)} * method denies read access to the file - * - * @see java.nio.file.attribute.Attributes#readBasicFileAttributes */ public boolean isFile() { SecurityManager security = System.getSecurityManager(); @@ -853,6 +861,13 @@ public class File * Returns the time that the file denoted by this abstract pathname was * last modified. * + *

Where it is required to distinguish an I/O exception from the case + * where {@code 0L} is returned, or where several attributes of the + * same file are required at the same time, or where the time of last + * access or the creation time are required, then the {@link + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) + * Files.readAttributes} method may be used. + * * @return A long value representing the time the file was * last modified, measured in milliseconds since the epoch * (00:00:00 GMT, January 1, 1970), or 0L if the @@ -862,8 +877,6 @@ public class File * If a security manager exists and its {@link * java.lang.SecurityManager#checkRead(java.lang.String)} * method denies read access to the file - * - * @see java.nio.file.attribute.Attributes#readBasicFileAttributes */ public long lastModified() { SecurityManager security = System.getSecurityManager(); @@ -877,6 +890,12 @@ public class File * Returns the length of the file denoted by this abstract pathname. * The return value is unspecified if this pathname denotes a directory. * + *

Where it is required to distinguish an I/O exception from the case + * that {@code 0L} is returned, or where several attributes of the same file + * are required at the same time, then the {@link + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) + * Files.readAttributes} method may be used. + * * @return The length, in bytes, of the file denoted by this abstract * pathname, or 0L if the file does not exist. Some * operating systems may return 0L for pathnames @@ -886,8 +905,6 @@ public class File * If a security manager exists and its {@link * java.lang.SecurityManager#checkRead(java.lang.String)} * method denies read access to the file - * - * @see java.nio.file.attribute.Attributes#readBasicFileAttributes */ public long length() { SecurityManager security = System.getSecurityManager(); @@ -937,11 +954,10 @@ public class File * this pathname denotes a directory, then the directory must be empty in * order to be deleted. * - *

Note that the {@link Path} class defines the {@link Path#delete - * delete} method to throw an {@link IOException} when a file cannot be - * deleted. This is useful for error reporting and to diagnose why a file - * cannot be deleted. The {@link #toPath toPath} method may be used to - * obtain a {@code Path} representing this abstract pathname. + *

Note that the {@link java.nio.file.Files} class defines the {@link + * java.nio.file.Files#delete(Path) delete} method to throw an {@link IOException} + * when a file cannot be deleted. This is useful for error reporting and to + * diagnose why a file cannot be deleted. * * @return true if and only if the file or directory is * successfully deleted; false otherwise @@ -1009,12 +1025,11 @@ public class File * will appear in any specific order; they are not, in particular, * guaranteed to appear in alphabetical order. * - *

Note that the {@link Path} class defines the {@link - * Path#newDirectoryStream newDirectoryStream} method to open a directory - * and iterate over the names of the files in the directory. This may use - * less resources when working with very large directories. The {@link - * #toPath toPath} method may be used to obtain a {@code Path} representing - * this abstract pathname. + *

Note that the {@link java.nio.file.Files} class defines the {@link + * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method to + * open a directory and iterate over the names of the files in the directory. + * This may use less resources when working with very large directories, and + * may be more responsive when working with remote directories. * * @return An array of strings naming the files and directories in the * directory denoted by this abstract pathname. The array will be @@ -1061,6 +1076,8 @@ public class File * If a security manager exists and its {@link * SecurityManager#checkRead(String)} method denies read access to * the directory + * + * @see java.nio.file.Files#newDirectoryStream(Path,String) */ public String[] list(FilenameFilter filter) { String names[] = list(); @@ -1095,12 +1112,11 @@ public class File * will appear in any specific order; they are not, in particular, * guaranteed to appear in alphabetical order. * - *

Note that the {@link Path} class defines the {@link - * Path#newDirectoryStream newDirectoryStream} method to open a directory - * and iterate over the names of the files in the directory. This may use - * less resources when working with very large directories. The {@link - * #toPath toPath} method may be used to obtain a {@code Path} representing - * this abstract pathname. + *

Note that the {@link java.nio.file.Files} class defines the {@link + * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method + * to open a directory and iterate over the names of the files in the + * directory. This may use less resources when working with very large + * directories. * * @return An array of abstract pathnames denoting the files and * directories in the directory denoted by this abstract pathname. @@ -1154,6 +1170,7 @@ public class File * the directory * * @since 1.2 + * @see java.nio.file.Files#newDirectoryStream(Path,String) */ public File[] listFiles(FilenameFilter filter) { String ss[] = list(); @@ -1191,6 +1208,7 @@ public class File * the directory * * @since 1.2 + * @see java.nio.file.Files#newDirectoryStream(Path,java.nio.file.DirectoryStream.Filter) */ public File[] listFiles(FileFilter filter) { String ss[] = list(); @@ -1207,12 +1225,6 @@ public class File /** * Creates the directory named by this abstract pathname. * - *

Note that the {@link Path} class defines the {@link Path#createDirectory - * createDirectory} method to throw an {@link IOException} when a directory - * cannot be created. This is useful for error reporting and to diagnose why - * a directory cannot be created. The {@link #toPath toPath} method may be - * used to obtain a {@code Path} representing this abstract pathname. - * * @return true if and only if the directory was * created; false otherwise * @@ -1278,10 +1290,9 @@ public class File * already exists. The return value should always be checked to make sure * that the rename operation was successful. * - *

Note that the {@link Path} class defines the {@link Path#moveTo - * moveTo} method to move or rename a file in a platform independent manner. - * The {@link #toPath toPath} method may be used to obtain a {@code Path} - * representing this abstract pathname. + *

Note that the {@link java.nio.file.Files} class defines the {@link + * java.nio.file.Files#move move} method to move or rename a file in a + * platform independent manner. * * @param dest The new abstract pathname for the named file * @@ -1369,10 +1380,9 @@ public class File * Sets the owner's or everybody's write permission for this abstract * pathname. * - *

The {@link java.nio.file.attribute.Attributes Attributes} class - * defines methods that operate on file attributes including file - * permissions. This may be used when finer manipulation of file permissions - * is required. + *

The {@link java.nio.file.Files} class defines methods that operate on + * file attributes including file permissions. This may be used when finer + * manipulation of file permissions is required. * * @param writable * If true, sets the access permission to allow write @@ -1437,10 +1447,9 @@ public class File * Sets the owner's or everybody's read permission for this abstract * pathname. * - *

The {@link java.nio.file.attribute.Attributes Attributes} class - * defines methods that operate on file attributes including file - * permissions. This may be used when finer manipulation of file permissions - * is required. + *

The {@link java.nio.file.Files} class defines methods that operate on + * file attributes including file permissions. This may be used when finer + * manipulation of file permissions is required. * * @param readable * If true, sets the access permission to allow read @@ -1511,10 +1520,9 @@ public class File * Sets the owner's or everybody's execute permission for this abstract * pathname. * - *

The {@link java.nio.file.attribute.Attributes Attributes} class - * defines methods that operate on file attributes including file - * permissions. This may be used when finer manipulation of file permissions - * is required. + *

The {@link java.nio.file.Files} class defines methods that operate on + * file attributes including file permissions. This may be used when finer + * manipulation of file permissions is required. * * @param executable * If true, sets the access permission to allow execute @@ -1646,6 +1654,7 @@ public class File * filesystem roots. * * @since 1.2 + * @see java.nio.file.FileStore */ public static File[] listRoots() { return fs.listRoots(); @@ -1753,7 +1762,7 @@ public class File /* -- Temporary files -- */ - static class TempDirectory { + private static class TempDirectory { private TempDirectory() { } // temporary directory location @@ -1880,11 +1889,12 @@ public class File * java.lang.String, java.io.File) * createTempFile(prefix, suffix, null)}. * - *

The {@link #createTemporaryFile(String,String,FileAttribute[])} method - * provides an alternative method to create an empty file in the - * temporary-file directory. Files created by that method may have more - * restrictive access permissions to files created by this method and so - * may be more suited to security-sensitive applications. + *

The {@link + * java.nio.file.Files#createTempFile(String,String,java.nio.file.attribute.FileAttribute[]) + * Files.createTempFile} method provides an alternative method to create an + * empty file in the temporary-file directory. Files created by that method + * may have more restrictive access permissions to files created by this + * method and so may be more suited to security-sensitive applications. * * @param prefix The prefix string to be used in generating the file's * name; must be at least three characters long @@ -1907,6 +1917,7 @@ public class File * method does not allow a file to be created * * @since 1.2 + * @see java.nio.file.Files#createTempDirectory(String,FileAttribute[]) */ public static File createTempFile(String prefix, String suffix) throws IOException @@ -1914,61 +1925,6 @@ public class File return createTempFile(prefix, suffix, null); } - /** - * Creates an empty file in the default temporary-file directory, using - * the given prefix and suffix to generate its name. - * - *

The {@code attrs} parameter is an optional array of {@link FileAttribute - * attributes} to set atomically when creating the file. Each attribute is - * identified by its {@link FileAttribute#name name}. If more than one attribute - * of the same name is included in the array then all but the last occurrence - * is ignored. - * - *

Where the {@code attrs} parameter does not specify access - * permissions to set atomically when creating the file, then the - * resulting file may have more restrictive access permissions than files - * created by the {@link #createTempFile(java.lang.String, java.lang.String)} - * method. - * - * @param prefix - * The prefix string to be used in generating the file's - * name; must be at least three characters long - * @param suffix - * The suffix string to be used in generating the file's - * name; may be {@code null}, in which case the suffix - * {@code ".tmp"} will be used - * @param attrs - * An optional list of file attributes to set atomically when creating - * the file - * - * @return An abstract pathname denoting a newly-created empty file - * - * @throws IllegalArgumentException - * If the {@code prefix} argument contains fewer than three - * characters - * @throws UnsupportedOperationException - * If the array contains an attribute that cannot be set atomically - * when creating the file - * @throws IOException - * If a file could not be created - * @throws SecurityException - * If a security manager exists and its {@link - * java.lang.SecurityManager#checkWrite(java.lang.String)} - * method does not allow a file to be created. - * - * @since 1.7 - */ - public static File createTemporaryFile(String prefix, - String suffix, - FileAttribute... attrs) - throws IOException - { - if (prefix.length() < 3) - throw new IllegalArgumentException("Prefix string too short"); - suffix = (suffix == null) ? ".tmp" : suffix; - return TempFileHelper.createFile(prefix, suffix, attrs); - } - /* -- Basic infrastructure -- */ /** @@ -2104,6 +2060,7 @@ public class File * path (see {@link java.nio.file.FileSystem#getPath FileSystem.getPath}) * * @since 1.7 + * @see Path#toFile */ public Path toPath() { Path result = filePath; @@ -2111,12 +2068,7 @@ public class File synchronized (this) { result = filePath; if (result == null) { - if (path.length() == 0) { - // assume default file system treats "." as current directory - result = Paths.get("."); - } else { - result = Paths.get(path); - } + result = FileSystems.getDefault().getPath(path); filePath = result; } } diff --git a/src/share/classes/java/io/FileInputStream.java b/src/share/classes/java/io/FileInputStream.java index 23530c19e1f5433b5a4681f3cdd6bf132a7f211d..da7ad18a5323ef9f0db499c614fc75cbb4c434a0 100644 --- a/src/share/classes/java/io/FileInputStream.java +++ b/src/share/classes/java/io/FileInputStream.java @@ -42,6 +42,7 @@ import sun.nio.ch.FileChannelImpl; * @see java.io.File * @see java.io.FileDescriptor * @see java.io.FileOutputStream + * @see java.nio.file.Files#newInputStream * @since JDK1.0 */ public diff --git a/src/share/classes/java/io/FileOutputStream.java b/src/share/classes/java/io/FileOutputStream.java index 3fe3a594fd220f5d749ffdfc469df8c4d07f2367..d714679164ad3098c731edcf7ee0160550c28ae7 100644 --- a/src/share/classes/java/io/FileOutputStream.java +++ b/src/share/classes/java/io/FileOutputStream.java @@ -46,6 +46,7 @@ import sun.nio.ch.FileChannelImpl; * @see java.io.File * @see java.io.FileDescriptor * @see java.io.FileInputStream + * @see java.nio.file.Files#newOutputStream * @since JDK1.0 */ public diff --git a/src/share/classes/java/io/FilePermission.java b/src/share/classes/java/io/FilePermission.java index 06b4f3bb267d823f49b4a9128d82732356fbace0..b5feb367e13ead2ad29c8ab3914428285a07a86c 100644 --- a/src/share/classes/java/io/FilePermission.java +++ b/src/share/classes/java/io/FilePermission.java @@ -72,7 +72,7 @@ import sun.security.util.SecurityConstants; *

readlink *
read link permission. Allows the target of a * symbolic link - * to be read by invoking the {@link java.nio.file.Path#readSymbolicLink + * to be read by invoking the {@link java.nio.file.Files#readSymbolicLink * readSymbolicLink } method. * *

diff --git a/src/share/classes/java/io/SerialCallbackContext.java b/src/share/classes/java/io/SerialCallbackContext.java index 90d022e53ea30641187b83f047ac6061a3c54ebf..f62bdbf9a3e4a46a4274a57ed486275bfd822997 100644 --- a/src/share/classes/java/io/SerialCallbackContext.java +++ b/src/share/classes/java/io/SerialCallbackContext.java @@ -54,5 +54,3 @@ thread = null; } } - - diff --git a/src/share/classes/java/nio/channels/FileChannel.java b/src/share/classes/java/nio/channels/FileChannel.java index 8dff4bfc31612c814b596d245217cc34514827eb..80961dd3f8e0df60221e527e8ee5760c278a3ec8 100644 --- a/src/share/classes/java/nio/channels/FileChannel.java +++ b/src/share/classes/java/nio/channels/FileChannel.java @@ -248,7 +248,7 @@ public abstract class FileChannel * FileSystemProvider#newFileChannel newFileChannel} method on the * provider that created the {@code Path}. * - * @param file + * @param path * The path of the file to open or create * @param options * Options specifying how the file is opened @@ -261,7 +261,7 @@ public abstract class FileChannel * @throws IllegalArgumentException * If the set contains an invalid combination of options * @throws UnsupportedOperationException - * If the {@code file} is associated with a provider that does not + * If the {@code path} is associated with a provider that does not * support creating file channels, or an unsupported open option is * specified, or the array contains an attribute that cannot be set * atomically when creating the file @@ -278,13 +278,13 @@ public abstract class FileChannel * * @since 1.7 */ - public static FileChannel open(Path file, + public static FileChannel open(Path path, Set options, FileAttribute... attrs) throws IOException { - FileSystemProvider provider = file.getFileSystem().provider(); - return provider.newFileChannel(file, options, attrs); + FileSystemProvider provider = path.getFileSystem().provider(); + return provider.newFileChannel(path, options, attrs); } private static final FileAttribute[] NO_ATTRIBUTES = new FileAttribute[0]; @@ -295,10 +295,12 @@ public abstract class FileChannel *

An invocation of this method behaves in exactly the same way as the * invocation *

-     *     fc.{@link #open(Path,Set,FileAttribute[]) open}(file, options, new FileAttribute<?>[0]);
+     *     fc.{@link #open(Path,Set,FileAttribute[]) open}(file, opts, new FileAttribute<?>[0]);
      * 
+ * where {@code opts} is a set of the options specified in the {@code + * options} array. * - * @param file + * @param path * The path of the file to open or create * @param options * Options specifying how the file is opened @@ -308,7 +310,7 @@ public abstract class FileChannel * @throws IllegalArgumentException * If the set contains an invalid combination of options * @throws UnsupportedOperationException - * If the {@code file} is associated with a provider that does not + * If the {@code path} is associated with a provider that does not * support creating file channels, or an unsupported open option is * specified * @throws IOException @@ -324,12 +326,12 @@ public abstract class FileChannel * * @since 1.7 */ - public static FileChannel open(Path file, OpenOption... options) + public static FileChannel open(Path path, OpenOption... options) throws IOException { Set set = new HashSet(options.length); Collections.addAll(set, options); - return open(file, set, NO_ATTRIBUTES); + return open(path, set, NO_ATTRIBUTES); } // -- Channel operations -- diff --git a/src/share/classes/java/nio/channels/SeekableByteChannel.java b/src/share/classes/java/nio/channels/SeekableByteChannel.java index 4e75723b26119e1f46009fedccc66c0998c6d616..c2378546370819bbca360401e98d308e2fbca4b9 100644 --- a/src/share/classes/java/nio/channels/SeekableByteChannel.java +++ b/src/share/classes/java/nio/channels/SeekableByteChannel.java @@ -47,7 +47,7 @@ import java.io.IOException; * so that method invocations on the implementation class can be chained. * * @since 1.7 - * @see java.nio.file.Path#newByteChannel + * @see java.nio.file.Files#newByteChannel */ public interface SeekableByteChannel diff --git a/src/share/classes/java/nio/file/AccessMode.java b/src/share/classes/java/nio/file/AccessMode.java index c040bec01c89d048eefda9ac18c86d1027db7956..43b06c25a64d31e40131178d59740a2d0937ab75 100644 --- a/src/share/classes/java/nio/file/AccessMode.java +++ b/src/share/classes/java/nio/file/AccessMode.java @@ -29,8 +29,6 @@ package java.nio.file; * Defines access modes used to test the accessibility of a file. * * @since 1.7 - * - * @see Path#checkAccess */ public enum AccessMode { diff --git a/src/share/classes/java/nio/file/CopyMoveHelper.java b/src/share/classes/java/nio/file/CopyMoveHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..70ca6ee50ad3ec5a5491151924461572048d7e16 --- /dev/null +++ b/src/share/classes/java/nio/file/CopyMoveHelper.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.nio.file; + +import java.nio.file.attribute.*; +import java.io.InputStream; +import java.io.IOException; + +/** + * Helper class to support copying or moving files when the source and target + * are associated with different providers. + */ + +class CopyMoveHelper { + private CopyMoveHelper() { } + + /** + * Parses the arguments for a file copy operation. + */ + private static class CopyOptions { + boolean replaceExisting = false; + boolean copyAttributes = false; + boolean followLinks = true; + + private CopyOptions() { } + + static CopyOptions parse(CopyOption... options) { + CopyOptions result = new CopyOptions(); + for (CopyOption option: options) { + if (option == StandardCopyOption.REPLACE_EXISTING) { + result.replaceExisting = true; + continue; + } + if (option == LinkOption.NOFOLLOW_LINKS) { + result.followLinks = false; + continue; + } + if (option == StandardCopyOption.COPY_ATTRIBUTES) { + result.copyAttributes = true; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new UnsupportedOperationException("'" + option + + "' is not a recognized copy option"); + } + return result; + } + } + + /** + * Converts the given array of options for moving a file to options suitable + * for copying the file when a move is implemented as copy + delete. + */ + private static CopyOption[] convertMoveToCopyOptions(CopyOption... options) + throws AtomicMoveNotSupportedException + { + int len = options.length; + CopyOption[] newOptions = new CopyOption[len+2]; + for (int i=0; i Objects of this type may be used with the {@link Path#copyTo copyTo} and - * {@link Path#moveTo moveTo} methods to configure how a file is copied or moved. + *

Objects of this type may be used with the {@link + * Files#copy(Path,Path,CopyOption[]) Files.copy(Path,Path,CopyOption...)}, + * {@link Files#copy(java.io.InputStream,Path,CopyOption[]) + * Files.copy(InputStream,Path,CopyOption...)} and {@link Files#move + * Files.move(Path,Path,CopyOption...)} methods to configure how a file is + * copied or moved. * *

The {@link StandardCopyOption} enumeration type defines the * standard options. diff --git a/src/share/classes/java/nio/file/DirectoryStream.java b/src/share/classes/java/nio/file/DirectoryStream.java index 5601c9d99a8c802fa687e7da92e1cedff753e517..d34f8dbd450781c84385b0dea101581597558eed 100644 --- a/src/share/classes/java/nio/file/DirectoryStream.java +++ b/src/share/classes/java/nio/file/DirectoryStream.java @@ -54,7 +54,7 @@ import java.io.IOException; * construct to ensure that the stream is closed: *

  *   Path dir = ...
- *   try (DirectoryStream<Path> stream = dir.newDirectoryStream()) {
+ *   try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
  *       for (Path entry: stream) {
  *           ...
  *       }
@@ -97,8 +97,8 @@ import java.io.IOException;
  * both the for-each and try-with-resources constructs.
  * 
  *   List<Path> listSourceFiles(Path dir) throws IOException {
- *       List<Path> result = new ArrayList<Path>();
- *       try (DirectoryStream<Path> stream = dir.newDirectoryStream("*.{c,h,cpp,hpp,java}")) {
+ *       List<Path> result = new ArrayList<>();
+ *       try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{c,h,cpp,hpp,java}")) {
  *           for (Path entry: stream) {
  *               result.add(entry);
  *           }
@@ -113,7 +113,7 @@ import java.io.IOException;
  *
  * @since 1.7
  *
- * @see Path#newDirectoryStream
+ * @see Files#newDirectoryStream(Path)
  */
 
 public interface DirectoryStream
@@ -122,9 +122,9 @@ public interface DirectoryStream
     /**
      * An interface that is implemented by objects that decide if a directory
      * entry should be accepted or filtered. A {@code Filter} is passed as the
-     * parameter to the {@link Path#newDirectoryStream(DirectoryStream.Filter)
-     * newDirectoryStream} method when opening a directory to iterate over the
-     * entries in the directory.
+     * parameter to the {@link Files#newDirectoryStream(Path,DirectoryStream.Filter)}
+     * method when opening a directory to iterate over the entries in the
+     * directory.
      *
      * @param        the type of the directory entry
      *
diff --git a/src/share/classes/java/nio/file/FileRef.java b/src/share/classes/java/nio/file/FileRef.java
deleted file mode 100644
index fea3b7c3dfe399505b6a931b3c1423e75061774d..0000000000000000000000000000000000000000
--- a/src/share/classes/java/nio/file/FileRef.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright (c) 2007, 2009, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-package java.nio.file;
-
-import java.nio.file.attribute.*;
-import java.util.Map;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.IOException;
-
-/**
- * A reference to a file.
- *
- * 

A {@code FileRef} is an object that locates a file and defines methods to - * open the file for reading or writing. It also provides access to associated - * metadata or file attributes. - * - * @since 1.7 - * @see java.nio.file.attribute.Attributes - * @see java.io.File#toPath - */ - -public interface FileRef { - - /** - * Opens the file referenced by this object, returning an input stream to - * read from the file. The stream will not be buffered, and is not required - * to support the {@link InputStream#mark mark} or {@link InputStream#reset - * reset} methods. The stream will be safe for access by multiple concurrent - * threads. Reading commences at the beginning of the file. - * - *

The {@code options} parameter determines how the file is opened. - * If no options are present then it is equivalent to opening the file with - * the {@link StandardOpenOption#READ READ} option. In addition to the {@code - * READ} option, an implementation may also support additional implementation - * specific options. - * - * @return an input stream to read bytes from the file - * - * @throws IllegalArgumentException - * if an invalid combination of options is specified - * @throws UnsupportedOperationException - * if an unsupported option is specified - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the file. - */ - InputStream newInputStream(OpenOption... options) throws IOException; - - /** - * Opens or creates the file located by this object for writing, returning - * an output stream to write bytes to the file. - * - *

The {@code options} parameter determines how the file is opened. - * If no options are present then this method creates a new file for writing - * or truncates an existing file. In addition to the {@link StandardOpenOption - * standard} options, an implementation may also support additional - * implementation specific options. - * - *

The resulting stream will not be buffered. The stream will be safe - * for access by multiple concurrent threads. - * - * @param options - * options specifying how the file is opened - * - * @return a new output stream - * - * @throws IllegalArgumentException - * if {@code options} contains an invalid combination of options - * @throws UnsupportedOperationException - * if an unsupported option is specified - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkWrite(String) checkWrite} - * method is invoked to check write access to the file. - */ - OutputStream newOutputStream(OpenOption... options) throws IOException; - - /** - * Returns a file attribute view of a given type. - * - *

A file attribute view provides a read-only or updatable view of a - * set of file attributes. This method is intended to be used where the file - * attribute view defines type-safe methods to read or update the file - * attributes. The {@code type} parameter is the type of the attribute view - * required and the method returns an instance of that type if supported. - * The {@link BasicFileAttributeView} type supports access to the basic - * attributes of a file. Invoking this method to select a file attribute - * view of that type will always return an instance of that class. - * - *

The {@code options} array may be used to indicate how symbolic links - * are handled by the resulting file attribute view for the case that the - * file is a symbolic link. By default, symbolic links are followed. If the - * option {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} is present then - * symbolic links are not followed. This option is ignored by implementations - * that do not support symbolic links. - * - * @param type - * the {@code Class} object corresponding to the file attribute view - * @param options - * options indicating how symbolic links are handled - * - * @return a file attribute view of the specified type, or {@code null} if - * the attribute view type is not available - * - * @throws UnsupportedOperationException - * If options contains an unsupported option. This exception is - * specified to allow the {@code LinkOption} enum be extended - * in future releases. - * - * @see Attributes#readBasicFileAttributes - */ - V getFileAttributeView(Class type, - LinkOption... options); - - /** - * Sets the value of a file attribute. - * - *

The {@code attribute} parameter identifies the attribute to be set - * and takes the form: - *

- * [view-name:]attribute-name - *
- * where square brackets [...] delineate an optional component and the - * character {@code ':'} stands for itself. - * - *

view-name is the {@link FileAttributeView#name name} of a {@link - * FileAttributeView} that identifies a set of file attributes. If not - * specified then it defaults to {@code "basic"}, the name of the file - * attribute view that identifies the basic set of file attributes common to - * many file systems. attribute-name is the name of the attribute - * within the set. - * - *

Usage Example: - * Suppose we want to set the DOS "hidden" attribute: - *

-     *    file.setAttribute("dos:hidden", true);
-     * 
- * - * @param attribute - * the attribute to set - * @param value - * the attribute value - * @param options - * options indicating how symbolic links are handled - * - * @throws UnsupportedOperationException - * if the attribute view is not available or it does not support - * updating the attribute - * @throws IllegalArgumentException - * if the attribute value is of the correct type but has an - * inappropriate value - * @throws ClassCastException - * If the attribute value is not of the expected type or is a - * collection containing elements that are not of the expected - * type - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, its {@link SecurityManager#checkWrite(String) checkWrite} - * method denies write access to the file. If this method is invoked - * to set security sensitive attributes then the security manager - * may be invoked to check for additional permissions. - */ - void setAttribute(String attribute, Object value, LinkOption... options) - throws IOException; - - /** - * Reads the value of a file attribute. - * - *

The {@code attribute} parameter identifies the attribute to be read - * and takes the form: - *

- * [view-name:]attribute-name - *
- * where square brackets [...] delineate an optional component and the - * character {@code ':'} stands for itself. - * - *

view-name is the {@link FileAttributeView#name name} of a {@link - * FileAttributeView} that identifies a set of file attributes. If not - * specified then it defaults to {@code "basic"}, the name of the file - * attribute view that identifies the basic set of file attributes common to - * many file systems. attribute-name is the name of the attribute. - * - *

The {@code options} array may be used to indicate how symbolic links - * are handled for the case that the file is a symbolic link. By default, - * symbolic links are followed and the file attribute of the final target - * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS - * NOFOLLOW_LINKS} is present then symbolic links are not followed and so - * the method returns the file attribute of the symbolic link. - * - *

Usage Example: - * Suppose we require the user ID of the file owner on a system that - * supports a "{@code unix}" view: - *

-     *    int uid = (Integer)file.getAttribute("unix:uid");
-     * 
- * - * @param attribute - * the attribute to read - * @param options - * options indicating how symbolic links are handled - * @return the attribute value or {@code null} if the attribute view - * is not available or it does not support reading the attribute - * - * reading the attribute - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, its {@link SecurityManager#checkRead(String) checkRead} - * method denies read access to the file. If this method is invoked - * to read security sensitive attributes then the security manager - * may be invoked to check for additional permissions. - */ - Object getAttribute(String attribute, LinkOption... options) throws IOException; - - /** - * Reads a set of file attributes as a bulk operation. - * - *

The {@code attributes} parameter identifies the attributes to be read - * and takes the form: - *

- * [view-name:]attribute-list - *
- * where square brackets [...] delineate an optional component and the - * character {@code ':'} stands for itself. - * - *

view-name is the {@link FileAttributeView#name name} of a {@link - * FileAttributeView} that identifies a set of file attributes. If not - * specified then it defaults to {@code "basic"}, the name of the file - * attribute view that identifies the basic set of file attributes common to - * many file systems. - * - *

The attribute-list component is a comma separated list of - * zero or more names of attributes to read. If the list contains the value - * {@code "*"} then all attributes are read. Attributes that are not supported - * are ignored and will not be present in the returned map. It is - * implementation specific if all attributes are read as an atomic operation - * with respect to other file system operations. - * - *

The following examples demonstrate possible values for the {@code - * attributes} parameter: - * - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
{@code "*"} Read all {@link BasicFileAttributes basic-file-attributes}.
{@code "size,lastModifiedTime,lastAccessTime"} Reads the file size, last modified time, and last access time - * attributes.
{@code "posix:*"} Read all {@link PosixFileAttributes POSIX-file-attributes}..
{@code "posix:permissions,owner,size"} Reads the POSX file permissions, owner, and file size.
- *
- * - *

The {@code options} array may be used to indicate how symbolic links - * are handled for the case that the file is a symbolic link. By default, - * symbolic links are followed and the file attribute of the final target - * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS - * NOFOLLOW_LINKS} is present then symbolic links are not followed and so - * the method returns the file attribute of the symbolic link. - * - * @param attributes - * The attributes to read - * @param options - * Options indicating how symbolic links are handled - * - * @return A map of the attributes returned; may be empty. The map's keys - * are the attribute names, its values are the attribute values - * - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, its {@link SecurityManager#checkRead(String) checkRead} - * method denies read access to the file. If this method is invoked - * to read security sensitive attributes then the security manager - * may be invoke to check for additional permissions. - */ - Map readAttributes(String attributes, LinkOption... options) - throws IOException; -} diff --git a/src/share/classes/java/nio/file/FileStore.java b/src/share/classes/java/nio/file/FileStore.java index 4a79cccdff5fbbea6e4b1e4e2cfe15749bc8f5cb..4284a8ad5e9fc43694a71880d74f4871e77bf5ce 100644 --- a/src/share/classes/java/nio/file/FileStore.java +++ b/src/share/classes/java/nio/file/FileStore.java @@ -32,16 +32,13 @@ import java.io.IOException; * Storage for files. A {@code FileStore} represents a storage pool, device, * partition, volume, concrete file system or other implementation specific means * of file storage. The {@code FileStore} for where a file is stored is obtained - * by invoking the {@link Path#getFileStore getFileStore} method, or all file + * by invoking the {@link Files#getFileStore getFileStore} method, or all file * stores can be enumerated by invoking the {@link FileSystem#getFileStores * getFileStores} method. * *

In addition to the methods defined by this class, a file store may support * one or more {@link FileStoreAttributeView FileStoreAttributeView} classes * that provide a read-only or updatable view of a set of file store attributes. - * File stores associated with the default provider support the {@link - * FileStoreSpaceAttributeView} to read the space related attributes of the - * file store. * * @since 1.7 */ @@ -86,6 +83,51 @@ public abstract class FileStore { */ public abstract boolean isReadOnly(); + /** + * Returns the size, in bytes, of the file store. + * + * @return the size of the file store, in bytes + * + * @throws IOException + * if an I/O error occurs + */ + public abstract long getTotalSpace() throws IOException; + + /** + * Returns the number of bytes available to this Java virtual machine on the + * file store. + * + *

The returned number of available bytes is a hint, but not a + * guarantee, that it is possible to use most or any of these bytes. The + * number of usable bytes is most likely to be accurate immediately + * after the space attributes are obtained. It is likely to be made inaccurate + * by any external I/O operations including those made on the system outside + * of this Java virtual machine. + * + * @return the number of bytes available + * + * @throws IOException + * if an I/O error occurs + */ + public abstract long getUsableSpace() throws IOException; + + /** + * Returns the number of unallocated bytes in the file store. + * + *

The returned number of unallocated bytes is a hint, but not a + * guarantee, that it is possible to use most or any of these bytes. The + * number of unallocated bytes is most likely to be accurate immediately + * after the space attributes are obtained. It is likely to be + * made inaccurate by any external I/O operations including those made on + * the system outside of this virtual machine. + * + * @return the number of unallocated bytes + * + * @throws IOException + * if an I/O error occurs + */ + public abstract long getUnallocatedSpace() throws IOException; + /** * Tells whether or not this file store supports the file attributes * identified by the given file attribute view. @@ -131,12 +173,6 @@ public abstract class FileStore { * The {@code type} parameter is the type of the attribute view required and * the method returns an instance of that type if supported. * - *

For {@code FileStore} objects created by the default provider, then - * the file stores support the {@link FileStoreSpaceAttributeView} that - * provides access to space attributes. In that case invoking this method - * with a parameter value of {@code FileStoreSpaceAttributeView.class} will - * always return an instance of that class. - * * @param type * the {@code Class} object corresponding to the attribute view * @@ -160,10 +196,6 @@ public abstract class FileStore { * a {@link FileStore AttributeView} that identifies a set of file attributes. * attribute-name is the name of the attribute. * - *

For {@code FileStore} objects created by the default provider, then - * the file stores support the {@link FileStoreSpaceAttributeView} that - * provides access to space attributes. - * *

Usage Example: * Suppose we want to know if ZFS compression is enabled (assuming the "zfs" * view is supported): diff --git a/src/share/classes/java/nio/file/FileSystem.java b/src/share/classes/java/nio/file/FileSystem.java index 8c7637a3947ae4431d96945d2dee873476de9f06..15b6ca2cd0fd0ebd3af38b380edb61414a223b50 100644 --- a/src/share/classes/java/nio/file/FileSystem.java +++ b/src/share/classes/java/nio/file/FileSystem.java @@ -38,8 +38,8 @@ import java.io.IOException; *

The default file system, obtained by invoking the {@link FileSystems#getDefault * FileSystems.getDefault} method, provides access to the file system that is * accessible to the Java virtual machine. The {@link FileSystems} class defines - * methods to create file systems that provide access to other types of file - * systems. + * methods to create file systems that provide access to other types of (custom) + * file systems. * *

A file system is the factory for several types of objects: * @@ -214,10 +214,9 @@ public abstract class FileSystem * Suppose we want to print the space usage for all file stores: *

      *     for (FileStore store: FileSystems.getDefault().getFileStores()) {
-     *         FileStoreSpaceAttributes attrs = Attributes.readFileStoreSpaceAttributes(store);
-     *         long total = attrs.totalSpace() / 1024;
-     *         long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / 1024;
-     *         long avail = attrs.usableSpace() / 1024;
+     *         long total = store.getTotalSpace() / 1024;
+     *         long used = (store.getTotalSpace() - store.getUnallocatedSpace()) / 1024;
+     *         long avail = store.getUsableSpace() / 1024;
      *         System.out.format("%-20s %12d %12d %12d%n", store, total, used, avail);
      *     }
      * 
@@ -244,7 +243,20 @@ public abstract class FileSystem public abstract Set supportedFileAttributeViews(); /** - * Converts a path string to a {@code Path}. + * Converts a path string, or a sequence of strings that when joined form + * a path string, to a {@code Path}. If {@code more} does not specify any + * elements then the value of the {@code first} parameter is the path string + * to convert. If {@code more} specifies one or more elements then each + * non-empty string, including {@code first}, is considered to be a sequence + * of name elements (see {@link Path}) and is joined to form a path string. + * The details as to how the Strings are joined is provider specific but + * typically they will be joined using the {@link #getSeparator + * name-separator} as the separator. For example, if the name separator is + * "{@code /}" and {@code getPath("/foo","bar","gus")} is invoked, then the + * path string {@code "/foo/bar/gus"} is converted to a {@code Path}. + * A {@code Path} representing an empty path is returned if {@code first} + * is the empty string and {@code more} does not contain any non-empty + * strings. * *

The parsing and conversion to a path object is inherently * implementation dependent. In the simplest case, the path string is rejected, @@ -270,18 +282,17 @@ public abstract class FileSystem * index} value indicating the first position in the {@code path} parameter * that caused the path string to be rejected. * - *

Invoking this method with an empty path string throws - * {@code InvalidPathException}. + * @param first + * the path string or initial part of the path string + * @param more + * additional strings to be joined to form the path string * - * @param path - * The path string - * - * @return A {@code Path} object + * @return the resulting {@code Path} * * @throws InvalidPathException * If the path string cannot be converted */ - public abstract Path getPath(String path); + public abstract Path getPath(String first, String... more); /** * Returns a {@code PathMatcher} that performs match operations on the @@ -290,9 +301,9 @@ public abstract class FileSystem * * The {@code syntaxAndPattern} parameter identifies the syntax and the * pattern and takes the form: - *

+ *
      * syntax:pattern
-     * 
+ *
* where {@code ':'} stands for itself. * *

A {@code FileSystem} implementation supports the "{@code glob}" and @@ -409,7 +420,7 @@ public abstract class FileSystem * @throws UnsupportedOperationException * If the pattern syntax is not known to the implementation * - * @see Path#newDirectoryStream(String) + * @see Files#newDirectoryStream(Path,String) */ public abstract PathMatcher getPathMatcher(String syntaxAndPattern); @@ -421,10 +432,8 @@ public abstract class FileSystem *

Usage Example: * Suppose we want to make "joe" the owner of a file: *

-     *     Path file = ...
-     *     UserPrincipal joe = file.getFileSystem().getUserPrincipalLookupService()
-     *         .lookupPrincipalByName("joe");
-     *     Attributes.setOwner(file, joe);
+     *     UserPrincipalLookupService lookupService = FileSystems.getDefault().getUserPrincipalLookupService();
+     *     Files.setOwner(path, lookupService.lookupPrincipalByName("joe"));
      * 
* * @throws UnsupportedOperationException diff --git a/src/share/classes/java/nio/file/FileSystems.java b/src/share/classes/java/nio/file/FileSystems.java index 3fc348b09f4d58b6e6d0cb9094fb242b33091857..3d7ab7a20f196b32f465c0f54433f86b43c54d33 100644 --- a/src/share/classes/java/nio/file/FileSystems.java +++ b/src/share/classes/java/nio/file/FileSystems.java @@ -164,8 +164,8 @@ public final class FileSystems { * to the first provider instance. The third provider class is instantiated * by invoking it with a reference to the second instance, and so on. The * last provider to be instantiated becomes the default provider; its {@code - * getFileSystem} method is invoked with the URI {@code "file:///"} to create - * the default file system. + * getFileSystem} method is invoked with the URI {@code "file:///"} to + * get a reference to the default file system. * *

Subsequent invocations of this method return the file system that was * returned by the first invocation. @@ -238,7 +238,7 @@ public final class FileSystems { * Suppose there is a provider identified by the scheme {@code "memory"} * installed: *

-     *   Map<String,String> env = new HashMap<String,String>();
+     *   Map<String,String> env = new HashMap<>();
      *   env.put("capacity", "16G");
      *   env.put("blockSize", "4k");
      *   FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
@@ -343,33 +343,25 @@ public final class FileSystems {
      *
      * 

This method makes use of specialized providers that create pseudo file * systems where the contents of one or more files is treated as a file - * system. The {@code file} parameter is a reference to an existing file - * and the {@code env} parameter is a map of provider specific properties to - * configure the file system. + * system. * *

This method iterates over the {@link FileSystemProvider#installedProviders() * installed} providers. It invokes, in turn, each provider's {@link - * FileSystemProvider#newFileSystem(FileRef,Map) newFileSystem(FileRef,Map)} method. - * If a provider returns a file system then the iteration terminates - * and the file system is returned. If none of the installed providers return - * a {@code FileSystem} then an attempt is made to locate the provider using - * the given class loader. If a provider returns a file system then the lookup - * terminates and the file system is returned. + * FileSystemProvider#newFileSystem(Path,Map) newFileSystem(Path,Map)} method + * with an empty map. If a provider returns a file system then the iteration + * terminates and the file system is returned. If none of the installed + * providers return a {@code FileSystem} then an attempt is made to locate + * the provider using the given class loader. If a provider returns a file + * system then the lookup terminates and the file system is returned. * - * @param file - * a reference to a file - * @param env - * a map of provider specific properties to configure the file system; - * may be empty + * @param path + * the path to the file * @param loader * the class loader to locate the provider or {@code null} to only * attempt to locate an installed provider * * @return a new file system * - * @throws IllegalArgumentException - * if the {@code env} parameter does not contain properties required - * by the provider, or a property value is invalid * @throws ProviderNotFoundException * if a provider supporting this file type cannot be located * @throws ServiceConfigurationError @@ -380,18 +372,18 @@ public final class FileSystems { * if a security manager is installed and it denies an unspecified * permission */ - public static FileSystem newFileSystem(FileRef file, - Map env, + public static FileSystem newFileSystem(Path path, ClassLoader loader) throws IOException { - if (file == null) + if (path == null) throw new NullPointerException(); + Map env = Collections.emptyMap(); // check installed providers for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { try { - return provider.newFileSystem(file, env); + return provider.newFileSystem(path, env); } catch (UnsupportedOperationException uoe) { } } @@ -402,7 +394,7 @@ public final class FileSystems { .load(FileSystemProvider.class, loader); for (FileSystemProvider provider: sl) { try { - return provider.newFileSystem(file, env); + return provider.newFileSystem(path, env); } catch (UnsupportedOperationException uoe) { } } diff --git a/src/share/classes/java/nio/file/FileTreeWalker.java b/src/share/classes/java/nio/file/FileTreeWalker.java index b3f422e6ac0ff03dc92ba4acfce5dbeaf0b5423f..fb3995315ccb853ba1cb0e58fbedd748e5540c3e 100644 --- a/src/share/classes/java/nio/file/FileTreeWalker.java +++ b/src/share/classes/java/nio/file/FileTreeWalker.java @@ -69,7 +69,8 @@ class FileTreeWalker { FileVisitResult result = walk(start, 0, new ArrayList()); - Objects.nonNull(result, "FileVisitor returned null"); + if (result == null) + throw new NullPointerException("FileVisitor returned null"); } /** @@ -102,12 +103,13 @@ class FileTreeWalker { if (attrs == null) { try { try { - attrs = Attributes.readBasicFileAttributes(file, linkOptions); + attrs = Files.readAttributes(file, BasicFileAttributes.class, linkOptions); } catch (IOException x1) { if (followLinks) { try { - attrs = Attributes - .readBasicFileAttributes(file, LinkOption.NOFOLLOW_LINKS); + attrs = Files.readAttributes(file, + BasicFileAttributes.class, + LinkOption.NOFOLLOW_LINKS); } catch (IOException x2) { exc = x2; } @@ -151,7 +153,7 @@ class FileTreeWalker { } else { boolean isSameFile = false; try { - isSameFile = file.isSameFile(ancestor.file()); + isSameFile = Files.isSameFile(file, ancestor.file()); } catch (IOException x) { // ignore } catch (SecurityException x) { @@ -175,7 +177,7 @@ class FileTreeWalker { // open the directory try { - stream = file.newDirectoryStream(); + stream = Files.newDirectoryStream(file); } catch (IOException x) { return visitor.visitFileFailed(file, x); } catch (SecurityException x) { @@ -212,7 +214,11 @@ class FileTreeWalker { } finally { try { stream.close(); - } catch (IOException x) { } + } catch (IOException e) { + // IOException will be notified to postVisitDirectory + if (ioe == null) + ioe = e; + } } // invoke postVisitDirectory last diff --git a/src/share/classes/java/nio/file/FileVisitor.java b/src/share/classes/java/nio/file/FileVisitor.java index bd6bac15d59eee9ce63aade3bca717587b70b651..3c507a8d443b89700c372c01063089dd15161ed5 100644 --- a/src/share/classes/java/nio/file/FileVisitor.java +++ b/src/share/classes/java/nio/file/FileVisitor.java @@ -30,8 +30,8 @@ import java.io.IOException; /** * A visitor of files. An implementation of this interface is provided to the - * {@link Files#walkFileTree walkFileTree} utility method to visit each file - * in a tree. + * {@link Files#walkFileTree Files.walkFileTree} methods to visit each file in + * a file tree. * *

Usage Examples: * Suppose we want to delete a file tree. In that case, each directory should @@ -43,19 +43,20 @@ import java.io.IOException; * public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) * throws IOException * { - * file.delete(); + * Files.delete(file); * return FileVisitResult.CONTINUE; * } * @Override * public FileVisitResult postVisitDirectory(Path dir, IOException e) * throws IOException * { - * if (e != null) { + * if (e == null) { + * Files.delete(dir); + * return FileVisitResult.CONTINUE; + * } else { * // directory iteration failed * throw e; * } - * dir.delete(); - * return FileVisitResult.CONTINUE; * } * }); *

@@ -72,10 +73,12 @@ import java.io.IOException; * public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) * throws IOException * { + * Path targetdir = target.resolve(source.relativize(dir)); * try { - * dir.copyTo(target.resolve(source.relativize(dir))); + * Files.copy(dir, targetdir); * } catch (FileAlreadyExistsException e) { - * // ignore + * if (!Files.isDirectory(targetdir)) + * throw e; * } * return CONTINUE; * } @@ -83,7 +86,7 @@ import java.io.IOException; * public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) * throws IOException * { - * file.copyTo(target.resolve(source.relativize(file))); + * Files.copy(file, target.resolve(source.relativize(file))); * return CONTINUE; * } * }); diff --git a/src/share/classes/java/nio/file/Files.java b/src/share/classes/java/nio/file/Files.java index a0f00855b7463852a08a7febc0fd0e0871a05df9..cb1fde29685aaa99bebbc33cbb7c82b4212af558 100644 --- a/src/share/classes/java/nio/file/Files.java +++ b/src/share/classes/java/nio/file/Files.java @@ -25,16 +25,32 @@ package java.nio.file; -import java.nio.file.spi.FileTypeDetector; import java.nio.file.attribute.*; +import java.nio.file.spi.FileSystemProvider; +import java.nio.file.spi.FileTypeDetector; +import java.nio.channels.SeekableByteChannel; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.io.IOException; import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; /** - * This class consists exclusively of static methods that operate on files or - * directories. + * This class consists exclusively of static methods that operate on files, + * directories, or other types of files. + * + *

In most cases, the methods defined here will delegate to the associated + * file system provider to perform the file operations. * * @since 1.7 */ @@ -42,91 +58,2420 @@ import java.security.PrivilegedAction; public final class Files { private Files() { } - // lazy loading of default and installed file type detectors - private static class DefaultFileTypeDetectorHolder { - static final FileTypeDetector defaultFileTypeDetector = - sun.nio.fs.DefaultFileTypeDetector.create(); - static final List installeDetectors = - loadInstalledDetectors(); + /** + * Returns the {@code FileSystemProvider} to delegate to. + */ + private static FileSystemProvider provider(Path path) { + return path.getFileSystem().provider(); + } - // loads all installed file type detectors - private static List loadInstalledDetectors() { - return AccessController - .doPrivileged(new PrivilegedAction>() { - @Override public List run() { - List list = new ArrayList(); - ServiceLoader loader = ServiceLoader - .load(FileTypeDetector.class, ClassLoader.getSystemClassLoader()); - for (FileTypeDetector detector: loader) { - list.add(detector); - } - return list; - }}); + // -- File contents -- + + /** + * Opens a file, returning an input stream to read from the file. The stream + * will not be buffered, and is not required to support the {@link + * InputStream#mark mark} or {@link InputStream#reset reset} methods. The + * stream will be safe for access by multiple concurrent threads. Reading + * commences at the beginning of the file. Whether the returned stream is + * asynchronously closeable and/or interruptible is highly + * file system provider specific and therefore not specified. + * + *

The {@code options} parameter determines how the file is opened. + * If no options are present then it is equivalent to opening the file with + * the {@link StandardOpenOption#READ READ} option. In addition to the {@code + * READ} option, an implementation may also support additional implementation + * specific options. + * + * @param path + * the path to the file to open + * @param options + * options specifying how the file is opened + * + * @return a new input stream + * + * @throws IllegalArgumentException + * if an invalid combination of options is specified + * @throws UnsupportedOperationException + * if an unsupported option is specified + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + public static InputStream newInputStream(Path path, OpenOption... options) + throws IOException + { + return provider(path).newInputStream(path, options); + } + + /** + * Opens or creates a file, returning an output stream that may be used to + * write bytes to the file. The resulting stream will not be buffered. The + * stream will be safe for access by multiple concurrent threads. Whether + * the returned stream is asynchronously closeable and/or + * interruptible is highly file system provider specific and + * therefore not specified. + * + *

This method opens or creates a file in exactly the manner specified + * by the {@link #newByteChannel(Path,Set,FileAttribute[]) newByteChannel} + * method with the exception that the {@link StandardOpenOption#READ READ} + * option may not be present in the array of options. If no options are + * present then this method works as if the {@link StandardOpenOption#CREATE + * CREATE}, {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING}, + * and {@link StandardOpenOption#WRITE WRITE} options are present. In other + * words, it opens the file for writing, creating the file if it doesn't + * exist, or initially truncating an existing {@link #isRegularFile + * regular-file} to a size of {@code 0} if it exists. + * + *

Usage Examples: + *

+     *     Path path = ...
+     *
+     *     // replace an existing file or create the file if it doesn't initially exist
+     *     OutputStream out = Files.newOutputStream(path);
+     *
+     *     // append to an existing file, fail if the file does not exist
+     *     out = Files.newOutputStream(path, APPEND);
+     *
+     *     // append to an existing file, create file if it doesn't initially exist
+     *     out = Files.newOutputStream(CREATE, APPEND);
+     *
+     *     // always create new file, failing if it already exists
+     *     out = Files.newOutputStream(CREATE_NEW);
+     * 
+ * + * @param path + * the path to the file to open or create + * @param options + * options specifying how the file is opened + * + * @return a new output stream + * + * @throws IllegalArgumentException + * if {@code options} contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported option is specified + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. The {@link + * SecurityManager#checkDelete(String) checkDelete} method is + * invoked to check delete access if the file is opened with the + * {@code DELETE_ON_CLOSE} option. + */ + public static OutputStream newOutputStream(Path path, OpenOption... options) + throws IOException + { + return provider(path).newOutputStream(path, options); + } + + /** + * Opens or creates a file, returning a seekable byte channel to access the + * file. + * + *

The {@code options} parameter determines how the file is opened. + * The {@link StandardOpenOption#READ READ} and {@link + * StandardOpenOption#WRITE WRITE} options determine if the file should be + * opened for reading and/or writing. If neither option (or the {@link + * StandardOpenOption#APPEND APPEND} option) is present then the file is + * opened for reading. By default reading or writing commence at the + * beginning of the file. + * + *

In the addition to {@code READ} and {@code WRITE}, the following + * options may be present: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Option Description
{@link StandardOpenOption#APPEND APPEND} If this option is present then the file is opened for writing and + * each invocation of the channel's {@code write} method first advances + * the position to the end of the file and then writes the requested + * data. Whether the advancement of the position and the writing of the + * data are done in a single atomic operation is system-dependent and + * therefore unspecified. This option may not be used in conjunction + * with the {@code READ} or {@code TRUNCATE_EXISTING} options.
{@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} If this option is present then the existing file is truncated to + * a size of 0 bytes. This option is ignored when the file is opened only + * for reading.
{@link StandardOpenOption#CREATE_NEW CREATE_NEW} If this option is present then a new file is created, failing if + * the file already exists or is a symbolic link. When creating a file the + * check for the existence of the file and the creation of the file if it + * does not exist is atomic with respect to other file system operations. + * This option is ignored when the file is opened only for reading.
{@link StandardOpenOption#CREATE CREATE} If this option is present then an existing file is opened if it + * exists, otherwise a new file is created. This option is ignored if the + * {@code CREATE_NEW} option is also present or the file is opened only + * for reading.
{@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} When this option is present then the implementation makes a + * best effort attempt to delete the file when closed by the + * {@link SeekableByteChannel#close close} method. If the {@code close} + * method is not invoked then a best effort attempt is made to + * delete the file when the Java virtual machine terminates.
{@link StandardOpenOption#SPARSE SPARSE} When creating a new file this option is a hint that the + * new file will be sparse. This option is ignored when not creating + * a new file.
{@link StandardOpenOption#SYNC SYNC} Requires that every update to the file's content or metadata be + * written synchronously to the underlying storage device. (see Synchronized I/O file + * integrity).
{@link StandardOpenOption#DSYNC DSYNC} Requires that every update to the file's content be written + * synchronously to the underlying storage device. (see Synchronized I/O file + * integrity).
+ * + *

An implementation may also support additional implementation specific + * options. + * + *

The {@code attrs} parameter is optional {@link FileAttribute + * file-attributes} to set atomically when a new file is created. + * + *

In the case of the default provider, the returned seekable byte channel + * is a {@link java.nio.channels.FileChannel}. + * + *

Usage Examples: + *

+     *     Path path = ...
+     *
+     *     // open file for reading
+     *     ReadableByteChannel rbc = Files.newByteChannel(path, EnumSet.of(READ)));
+     *
+     *     // open file for writing to the end of an existing file, creating
+     *     // the file if it doesn't already exist
+     *     WritableByteChannel wbc = Files.newByteChannel(path, EnumSet.of(CREATE,APPEND));
+     *
+     *     // create file with initial permissions, opening it for both reading and writing
+     *     {@code FileAttribute<> perms = ...}
+     *     SeekableByteChannel sbc = Files.newByteChannel(path, EnumSet.of(CREATE_NEW,READ,WRITE), perms);
+     * 
+ * + * @param path + * the path to the file to open or create + * @param options + * options specifying how the file is opened + * @param attrs + * an optional list of file attributes to set atomically when + * creating the file + * + * @return a new seekable byte channel + * + * @throws IllegalArgumentException + * if the set contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported open option is specified or the array contains + * attributes that cannot be set atomically when creating the file + * @throws FileAlreadyExistsException + * if a file of that name already exists and the {@link + * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified + * (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the path if the file is + * opened for reading. The {@link SecurityManager#checkWrite(String) + * checkWrite} method is invoked to check write access to the path + * if the file is opened for writing. The {@link + * SecurityManager#checkDelete(String) checkDelete} method is + * invoked to check delete access if the file is opened with the + * {@code DELETE_ON_CLOSE} option. + * + * @see java.nio.channels.FileChannel#open(Path,Set,FileAttribute[]) + */ + public static SeekableByteChannel newByteChannel(Path path, + Set options, + FileAttribute... attrs) + throws IOException + { + return provider(path).newByteChannel(path, options, attrs); + } + + /** + * Opens or creates a file, returning a seekable byte channel to access the + * file. + * + *

This method opens or creates a file in exactly the manner specified + * by the {@link #newByteChannel(Path,Set,FileAttribute[]) newByteChannel} + * method. + * + * @param path + * the path to the file to open or create + * @param options + * options specifying how the file is opened + * + * @return a new seekable byte channel + * + * @throws IllegalArgumentException + * if the set contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported open option is specified + * @throws FileAlreadyExistsException + * if a file of that name already exists and the {@link + * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified + * (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the path if the file is + * opened for reading. The {@link SecurityManager#checkWrite(String) + * checkWrite} method is invoked to check write access to the path + * if the file is opened for writing. The {@link + * SecurityManager#checkDelete(String) checkDelete} method is + * invoked to check delete access if the file is opened with the + * {@code DELETE_ON_CLOSE} option. + * + * @see java.nio.channels.FileChannel#open(Path,OpenOption[]) + */ + public static SeekableByteChannel newByteChannel(Path path, OpenOption... options) + throws IOException + { + Set set = new HashSet(options.length); + Collections.addAll(set, options); + return newByteChannel(path, set); + } + + // -- Directories -- + + /** + * Opens a directory, returning a {@link DirectoryStream} to iterate over + * all entries in the directory. The elements returned by the directory + * stream's {@link DirectoryStream#iterator iterator} are of type {@code + * Path}, each one representing an entry in the directory. The {@code Path} + * objects are obtained as if by {@link Path#resolve(Path) resolving} the + * name of the directory entry against {@code dir}. + * + *

When not using the try-with-resources construct, then directory + * stream's {@code close} method should be invoked after iteration is + * completed so as to free any resources held for the open directory. + * + *

When an implementation supports operations on entries in the + * directory that execute in a race-free manner then the returned directory + * stream is a {@link SecureDirectoryStream}. + * + * @param dir + * the path to the directory + * + * @return a new and open {@code DirectoryStream} object + * + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + */ + public static DirectoryStream newDirectoryStream(Path dir) + throws IOException + { + return provider(dir).newDirectoryStream(dir, new DirectoryStream.Filter() { + @Override + public boolean accept(Path entry) { + return true; + } + }); + } + + /** + * Opens a directory, returning a {@link DirectoryStream} to iterate over + * the entries in the directory. The elements returned by the directory + * stream's {@link DirectoryStream#iterator iterator} are of type {@code + * Path}, each one representing an entry in the directory. The {@code Path} + * objects are obtained as if by {@link Path#resolve(Path) resolving} the + * name of the directory entry against {@code dir}. The entries returned by + * the iterator are filtered by matching the {@code String} representation + * of their file names against the given globbing pattern. + * + *

For example, suppose we want to iterate over the files ending with + * ".java" in a directory: + *

+     *     Path dir = ...
+     *     try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.java")) {
+     *         :
+     *     }
+     * 
+ * + *

The globbing pattern is specified by the {@link + * FileSystem#getPathMatcher getPathMatcher} method. + * + *

When not using the try-with-resources construct, then directory + * stream's {@code close} method should be invoked after iteration is + * completed so as to free any resources held for the open directory. + * + *

When an implementation supports operations on entries in the + * directory that execute in a race-free manner then the returned directory + * stream is a {@link SecureDirectoryStream}. + * + * @param dir + * the path to the directory + * @param glob + * the glob pattern + * + * @return a new and open {@code DirectoryStream} object + * + * @throws java.util.regex.PatternSyntaxException + * if the pattern is invalid + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + */ + public static DirectoryStream newDirectoryStream(Path dir, String glob) + throws IOException + { + // avoid creating a matcher if all entries are required. + if (glob.equals("*")) + return newDirectoryStream(dir); + + // create a matcher and return a filter that uses it. + FileSystem fs = dir.getFileSystem(); + final PathMatcher matcher = fs.getPathMatcher("glob:" + glob); + DirectoryStream.Filter filter = new DirectoryStream.Filter() { + @Override + public boolean accept(Path entry) { + return matcher.matches(entry.getFileName()); + } + }; + return fs.provider().newDirectoryStream(dir, filter); + } + + /** + * Opens a directory, returning a {@link DirectoryStream} to iterate over + * the entries in the directory. The elements returned by the directory + * stream's {@link DirectoryStream#iterator iterator} are of type {@code + * Path}, each one representing an entry in the directory. The {@code Path} + * objects are obtained as if by {@link Path#resolve(Path) resolving} the + * name of the directory entry against {@code dir}. The entries returned by + * the iterator are filtered by the given {@link DirectoryStream.Filter + * filter}. + * + *

When not using the try-with-resources construct, then directory + * stream's {@code close} method should be invoked after iteration is + * completed so as to free any resources held for the open directory. + * + *

Where the filter terminates due to an uncaught error or runtime + * exception then it is propagated to the {@link Iterator#hasNext() + * hasNext} or {@link Iterator#next() next} method. Where an {@code + * IOException} is thrown, it results in the {@code hasNext} or {@code + * next} method throwing a {@link DirectoryIteratorException} with the + * {@code IOException} as the cause. + * + *

When an implementation supports operations on entries in the + * directory that execute in a race-free manner then the returned directory + * stream is a {@link SecureDirectoryStream}. + * + *

Usage Example: + * Suppose we want to iterate over the files in a directory that are + * larger than 8K. + *

+     *     DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
+     *         public boolean accept(Path file) throws IOException {
+     *             return (Files.size(file) > 8192L);
+     *         }
+     *     };
+     *     Path dir = ...
+     *     try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
+     *         :
+     *     }
+     * 
+ * + * @param dir + * the path to the directory + * @param filter + * the directory stream filter + * + * @return a new and open {@code DirectoryStream} object + * + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + */ + public static DirectoryStream newDirectoryStream(Path dir, + DirectoryStream.Filter filter) + throws IOException + { + return provider(dir).newDirectoryStream(dir, filter); + } + + // -- Creation and deletion -- + + /** + * Creates a new and empty file, failing if the file already exists. The + * check for the existence of the file and the creation of the new file if + * it does not exist are a single operation that is atomic with respect to + * all other filesystem activities that might affect the directory. + * + *

The {@code attrs} parameter is optional {@link FileAttribute + * file-attributes} to set atomically when creating the file. Each attribute + * is identified by its {@link FileAttribute#name name}. If more than one + * attribute of the same name is included in the array then all but the last + * occurrence is ignored. + * + * @param path + * the path to the file to create + * @param attrs + * an optional list of file attributes to set atomically when + * creating the file + * + * @return the file + * + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the file + * @throws FileAlreadyExistsException + * if a file of that name already exists + * (optional specific exception) + * @throws IOException + * if an I/O error occurs or the parent directory does not exist + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the new file. + */ + public static Path createFile(Path path, FileAttribute... attrs) + throws IOException + { + EnumSet options = + EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE); + newByteChannel(path, options, attrs).close(); + return path; + } + + /** + * Creates a new directory. The check for the existence of the file and the + * creation of the directory if it does not exist are a single operation + * that is atomic with respect to all other filesystem activities that might + * affect the directory. The {@link #createDirectories createDirectories} + * method should be used where it is required to create all nonexistent + * parent directories first. + * + *

The {@code attrs} parameter is optional {@link FileAttribute + * file-attributes} to set atomically when creating the directory. Each + * attribute is identified by its {@link FileAttribute#name name}. If more + * than one attribute of the same name is included in the array then all but + * the last occurrence is ignored. + * + * @param dir + * the directory to create + * @param attrs + * an optional list of file attributes to set atomically when + * creating the directory + * + * @return the directory + * + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the directory + * @throws FileAlreadyExistsException + * if a directory could not otherwise be created because a file of + * that name already exists (optional specific exception) + * @throws IOException + * if an I/O error occurs or the parent directory does not exist + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the new directory. + */ + public static Path createDirectory(Path dir, FileAttribute... attrs) + throws IOException + { + provider(dir).createDirectory(dir, attrs); + return dir; + } + + /** + * Creates a directory by creating all nonexistent parent directories first. + * Unlike the {@link #createDirectory createDirectory} method, an exception + * is not thrown if the directory could not be created because it already + * exists. + * + *

The {@code attrs} parameter is optional {@link FileAttribute + * file-attributes} to set atomically when creating the nonexistent + * directories. Each file attribute is identified by its {@link + * FileAttribute#name name}. If more than one attribute of the same name is + * included in the array then all but the last occurrence is ignored. + * + *

If this method fails, then it may do so after creating some, but not + * all, of the parent directories. + * + * @param dir + * the directory to create + * + * @param attrs + * an optional list of file attributes to set atomically when + * creating the directory + * + * @return the directory + * + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the directory + * @throws FileAlreadyExistsException + * if {@code dir} exists but is not a directory (optional specific + * exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * in the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked prior to attempting to create a directory and + * its {@link SecurityManager#checkRead(String) checkRead} is + * invoked for each parent directory that is checked. If {@code + * dir} is not an absolute path then its {@link Path#toAbsolutePath + * toAbsolutePath} may need to be invoked to get its absolute path. + * This may invoke the security manager's {@link + * SecurityManager#checkPropertyAccess(String) checkPropertyAccess} + * method to check access to the system property {@code user.dir} + */ + public static Path createDirectories(Path dir, FileAttribute... attrs) + throws IOException + { + // attempt to create the directory + try { + createAndCheckIsDirectory(dir, attrs); + return dir; + } catch (FileAlreadyExistsException x) { + // file exists and is not a directory + throw x; + } catch (IOException x) { + // parent may not exist or other reason + } + SecurityException se = null; + try { + dir = dir.toAbsolutePath(); + } catch (SecurityException x) { + // don't have permission to get absolute path + se = x; + } + // find a decendent that exists + Path parent = dir.getParent(); + while (parent != null) { + try { + provider(parent).checkAccess(parent); + break; + } catch (NoSuchFileException x) { + // does not exist + } + parent = parent.getParent(); + } + if (parent == null) { + // unable to find existing parent + if (se != null) + throw se; + throw new IOException("Root directory does not exist"); + } + + // create directories + Path child = parent; + for (Path name: parent.relativize(dir)) { + child = child.resolve(name); + createAndCheckIsDirectory(child, attrs); + } + return dir; + } + + /** + * Used by createDirectories to attempt to create a directory. A no-op + * if the directory already exists. + */ + private static void createAndCheckIsDirectory(Path dir, + FileAttribute... attrs) + throws IOException + { + try { + createDirectory(dir, attrs); + } catch (FileAlreadyExistsException x) { + if (!isDirectory(dir, LinkOption.NOFOLLOW_LINKS)) + throw x; + } + } + + /** + * Creates a new empty file in the specified directory, using the given + * prefix and suffix strings to generate its name. The resulting + * {@code Path} is associated with the same {@code FileSystem} as the given + * directory. + * + *

The details as to how the name of the file is constructed is + * implementation dependent and therefore not specified. Where possible + * the {@code prefix} and {@code suffix} are used to construct candidate + * names in the same manner as the {@link + * java.io.File#createTempFile(String,String,File)} method. + * + *

As with the {@code File.createTempFile} methods, this method is only + * part of a temporary-file facility. Where used as a work files, + * the resulting file may be opened using the {@link + * StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} option so that the + * file is deleted when the appropriate {@code close} method is invoked. + * Alternatively, a {@link Runtime#addShutdownHook shutdown-hook}, or the + * {@link java.io.File#deleteOnExit} mechanism may be used to delete the + * file automatically. + * + *

The {@code attrs} parameter is optional {@link FileAttribute + * file-attributes} to set atomically when creating the file. Each attribute + * is identified by its {@link FileAttribute#name name}. If more than one + * attribute of the same name is included in the array then all but the last + * occurrence is ignored. When no file attributes are specified, then the + * resulting file may have more restrictive access permissions to files + * created by the {@link java.io.File#createTempFile(String,String,File)} + * method. + * + * @param dir + * the path to directory in which to create the file + * @param prefix + * the prefix string to be used in generating the file's name; + * may be {@code null} + * @param suffix + * the suffix string to be used in generating the file's name; + * may be {@code null}, in which case "{@code .tmp}" is used + * @param attrs + * an optional list of file attributes to set atomically when + * creating the file + * + * @return the path to the newly created file that did not exist before + * this method was invoked + * + * @throws IllegalArgumentException + * if the prefix or suffix parameters cannot be used to generate + * a candidate file name + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the directory + * @throws IOException + * if an I/O error occurs or {@code dir} does not exist + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. + */ + public static Path createTempFile(Path dir, + String prefix, + String suffix, + FileAttribute... attrs) + throws IOException + { + return TempFileHelper.createTempFile(dir, prefix, suffix, attrs); + } + + /** + * Creates an empty file in the default temporary-file directory, using + * the given prefix and suffix to generate its name. The resulting {@code + * Path} is associated with the default {@code FileSystem}. + * + *

This method works in exactly the manner specified by the + * {@link #createTempFile(Path,String,String,FileAttribute[])} method for + * the case that the {@code dir} parameter is the temporary-file directory. + * + * @param prefix + * the prefix string to be used in generating the file's name; + * may be {@code null} + * @param suffix + * the suffix string to be used in generating the file's name; + * may be {@code null}, in which case "{@code .tmp}" is used + * @param attrs + * an optional list of file attributes to set atomically when + * creating the file + * + * @return the path to the newly created file that did not exist before + * this method was invoked + * + * @throws IllegalArgumentException + * if the prefix or suffix parameters cannot be used to generate + * a candidate file name + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the directory + * @throws IOException + * if an I/O error occurs or the temporary-file directory does not + * exist + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. + */ + public static Path createTempFile(String prefix, + String suffix, + FileAttribute... attrs) + throws IOException + { + return TempFileHelper.createTempFile(null, prefix, suffix, attrs); + } + + /** + * Creates a new directory in the specified directory, using the given + * prefix to generate its name. The resulting {@code Path} is associated + * with the same {@code FileSystem} as the given directory. + * + *

The details as to how the name of the directory is constructed is + * implementation dependent and therefore not specified. Where possible + * the {@code prefix} is used to construct candidate names. + * + *

As with the {@code createTempFile} methods, this method is only + * part of a temporary-file facility. A {@link Runtime#addShutdownHook + * shutdown-hook}, or the {@link java.io.File#deleteOnExit} mechanism may be + * used to delete the directory automatically. + * + *

The {@code attrs} parameter is optional {@link FileAttribute + * file-attributes} to set atomically when creating the directory. Each + * attribute is identified by its {@link FileAttribute#name name}. If more + * than one attribute of the same name is included in the array then all but + * the last occurrence is ignored. + * + * @param dir + * the path to directory in which to create the directory + * @param prefix + * the prefix string to be used in generating the directory's name; + * may be {@code null} + * @param attrs + * an optional list of file attributes to set atomically when + * creating the directory + * + * @return the path to the newly created directory that did not exist before + * this method was invoked + * + * @throws IllegalArgumentException + * if the prefix cannot be used to generate a candidate directory name + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the directory + * @throws IOException + * if an I/O error occurs or {@code dir} does not exist + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access when creating the + * directory. + */ + public static Path createTempDirectory(Path dir, + String prefix, + FileAttribute... attrs) + throws IOException + { + return TempFileHelper.createTempDirectory(dir, prefix, attrs); + } + + /** + * Creates a new directory in the default temporary-file directory, using + * the given prefix and suffix to generate its name. The resulting {@code + * Path} is associated with the default {@code FileSystem}. + * + *

This method works in exactly the manner specified by {@link + * #createTempDirectory(Path,String,FileAttribute[])} method for the case + * that the {@code dir} parameter is the temporary-file directory. + * + * @param prefix + * the prefix string to be used in generating the directory's name; + * may be {@code null} + * @param attrs + * an optional list of file attributes to set atomically when + * creating the directory + * + * @return the path to the newly created directory that did not exist before + * this method was invoked + * + * @throws IllegalArgumentException + * if the prefix cannot be used to generate a candidate directory name + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the directory + * @throws IOException + * if an I/O error occurs or the temporary-file directory does not + * exist + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access when creating the + * directory. + */ + public static Path createTempDirectory(String prefix, + FileAttribute... attrs) + throws IOException + { + return TempFileHelper.createTempDirectory(null, prefix, attrs); + } + + /** + * Creates a symbolic link to a target (optional operation). + * + *

The {@code target} parameter is the target of the link. It may be an + * {@link Path#isAbsolute absolute} or relative path and may not exist. When + * the target is a relative path then file system operations on the resulting + * link are relative to the path of the link. + * + *

The {@code attrs} parameter is optional {@link FileAttribute + * attributes} to set atomically when creating the link. Each attribute is + * identified by its {@link FileAttribute#name name}. If more than one attribute + * of the same name is included in the array then all but the last occurrence + * is ignored. + * + *

Where symbolic links are supported, but the underlying {@link FileStore} + * does not support symbolic links, then this may fail with an {@link + * IOException}. Additionally, some operating systems may require that the + * Java virtual machine be started with implementation specific privileges to + * create symbolic links, in which case this method may throw {@code IOException}. + * + * @param link + * the path of the symbolic link to create + * @param target + * the target of the symbolic link + * @param attrs + * the array of attributes to set atomically when creating the + * symbolic link + * + * @return the path to the symbolic link + * + * @throws UnsupportedOperationException + * if the implementation does not support symbolic links or the + * array contains an attribute that cannot be set atomically when + * creating the symbolic link + * @throws FileAlreadyExistsException + * if a file with the name already exists (optional specific + * exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager + * is installed, it denies {@link LinkPermission}("symbolic") + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the path of the symbolic link. + */ + public static Path createSymbolicLink(Path link, Path target, + FileAttribute... attrs) + throws IOException + { + provider(link).createSymbolicLink(link, target, attrs); + return link; + } + + /** + * Creates a new link (directory entry) for an existing file (optional + * operation). + * + *

The {@code link} parameter locates the directory entry to create. + * The {@code existing} parameter is the path to an existing file. This + * method creates a new directory entry for the file so that it can be + * accessed using {@code link} as the path. On some file systems this is + * known as creating a "hard link". Whether the file attributes are + * maintained for the file or for each directory entry is file system + * specific and therefore not specified. Typically, a file system requires + * that all links (directory entries) for a file be on the same file system. + * Furthermore, on some platforms, the Java virtual machine may require to + * be started with implementation specific privileges to create hard links + * or to create links to directories. + * + * @param link + * the link (directory entry) to create + * @param existing + * a path to an existing file + * + * @return the path to the link (directory entry) + * + * @throws UnsupportedOperationException + * if the implementation does not support adding an existing file + * to a directory + * @throws FileAlreadyExistsException + * if the entry could not otherwise be created because a file of + * that name already exists (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager + * is installed, it denies {@link LinkPermission}("hard") + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to either the link or the + * existing file. + */ + public static Path createLink(Path link, Path existing) throws IOException { + provider(link).createLink(link, existing); + return link; + } + + /** + * Deletes a file. + * + *

An implementation may require to examine the file to determine if the + * file is a directory. Consequently this method may not be atomic with respect + * to other file system operations. If the file is a symbolic link then the + * symbolic link itself, not the final target of the link, is deleted. + * + *

If the file is a directory then the directory must be empty. In some + * implementations a directory has entries for special files or links that + * are created when the directory is created. In such implementations a + * directory is considered empty when only the special entries exist. + * This method can be used with the {@link #walkFileTree walkFileTree} + * method to delete a directory and all entries in the directory, or an + * entire file-tree where required. + * + *

On some operating systems it may not be possible to remove a file when + * it is open and in use by this Java virtual machine or other programs. + * + * @param path + * the path to the file to delete + * + * @throws NoSuchFileException + * if the file does not exist (optional specific exception) + * @throws DirectoryNotEmptyException + * if the file is a directory and could not otherwise be deleted + * because the directory is not empty (optional specific + * exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkDelete(String)} method + * is invoked to check delete access to the file + */ + public static void delete(Path path) throws IOException { + provider(path).delete(path); + } + + /** + * Deletes a file if it exists. + * + *

As with the {@link #delete(Path) delete(Path)} method, an + * implementation may need to examine the file to determine if the file is a + * directory. Consequently this method may not be atomic with respect to + * other file system operations. If the file is a symbolic link, then the + * symbolic link itself, not the final target of the link, is deleted. + * + *

If the file is a directory then the directory must be empty. In some + * implementations a directory has entries for special files or links that + * are created when the directory is created. In such implementations a + * directory is considered empty when only the special entries exist. + * + *

On some operating systems it may not be possible to remove a file when + * it is open and in use by this Java virtual machine or other programs. + * + * @param path + * the path to the file to delete + * + * @return {@code true} if the file was deleted by this method; {@code + * false} if the file could not be deleted because it did not + * exist + * + * @throws DirectoryNotEmptyException + * if the file is a directory and could not otherwise be deleted + * because the directory is not empty (optional specific + * exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkDelete(String)} method + * is invoked to check delete access to the file. + */ + public static boolean deleteIfExists(Path path) throws IOException { + return provider(path).deleteIfExists(path); + } + + // -- Copying and moving files -- + + /** + * Copy a file to a target file. + * + *

This method copies a file to the target file with the {@code + * options} parameter specifying how the copy is performed. By default, the + * copy fails if the target file already exists or is a symbolic link, + * except if the source and target are the {@link #isSameFile same} file, in + * which case the method completes without copying the file. File attributes + * are not required to be copied to the target file. If symbolic links are + * supported, and the file is a symbolic link, then the final target of the + * link is copied. If the file is a directory then it creates an empty + * directory in the target location (entries in the directory are not + * copied). This method can be used with the {@link #walkFileTree + * walkFileTree} method to copy a directory and all entries in the directory, + * or an entire file-tree where required. + * + *

The {@code options} parameter may include any of the following: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Option Description
{@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} If the target file exists, then the target file is replaced if it + * is not a non-empty directory. If the target file exists and is a + * symbolic link, then the symbolic link itself, not the target of + * the link, is replaced.
{@link StandardCopyOption#COPY_ATTRIBUTES COPY_ATTRIBUTES} Attempts to copy the file attributes associated with this file to + * the target file. The exact file attributes that are copied is platform + * and file system dependent and therefore unspecified. Minimally, the + * {@link BasicFileAttributes#lastModifiedTime last-modified-time} is + * copied to the target file if supported by both the source and target + * file store. Copying of file timestamps may result in precision + * loss.
{@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} Symbolic links are not followed. If the file is a symbolic link, + * then the symbolic link itself, not the target of the link, is copied. + * It is implementation specific if file attributes can be copied to the + * new link. In other words, the {@code COPY_ATTRIBUTES} option may be + * ignored when copying a symbolic link.
+ * + *

An implementation of this interface may support additional + * implementation specific options. + * + *

Copying a file is not an atomic operation. If an {@link IOException} + * is thrown then it possible that the target file is incomplete or some of + * its file attributes have not been copied from the source file. When the + * {@code REPLACE_EXISTING} option is specified and the target file exists, + * then the target file is replaced. The check for the existence of the file + * and the creation of the new file may not be atomic with respect to other + * file system activities. + * + *

Usage Example: + * Suppose we want to copy a file into a directory, giving it the same file + * name as the source file: + *

+     *     Path source = ...
+     *     Path newdir = ...
+     *     Files.copy(source, newdir.resolve(source.getFileName());
+     * 
+ * + * @param source + * the path to the file to copy + * @param target + * the path to the target file (may be associated with a different + * provider to the source path) + * @param options + * options specifying how the copy should be done + * + * @return the path to the target file + * + * @throws UnsupportedOperationException + * if the array contains a copy option that is not supported + * @throws FileAlreadyExistsException + * if the target file exists but cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified (optional + * specific exception) + * @throws DirectoryNotEmptyException + * the {@code REPLACE_EXISTING} option is specified but the file + * cannot be replaced because it is a non-empty directory + * (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the source file, the + * {@link SecurityManager#checkWrite(String) checkWrite} is invoked + * to check write access to the target file. If a symbolic link is + * copied the security manager is invoked to check {@link + * LinkPermission}{@code ("symbolic")}. + */ + public static Path copy(Path source, Path target, CopyOption... options) + throws IOException + { + FileSystemProvider provider = provider(source); + if (provider(target) == provider) { + // same provider + provider.copy(source, target, options); + } else { + // different providers + CopyMoveHelper.copyToForeignTarget(source, target, options); + } + return target; + } + + /** + * Move or rename a file to a target file. + * + *

By default, this method attempts to move the file to the target + * file, failing if the target file exists except if the source and + * target are the {@link #isSameFile same} file, in which case this method + * has no effect. If the file is a symbolic link then the symbolic link + * itself, not the target of the link, is moved. This method may be + * invoked to move an empty directory. In some implementations a directory + * has entries for special files or links that are created when the + * directory is created. In such implementations a directory is considered + * empty when only the special entries exist. When invoked to move a + * directory that is not empty then the directory is moved if it does not + * require moving the entries in the directory. For example, renaming a + * directory on the same {@link FileStore} will usually not require moving + * the entries in the directory. When moving a directory requires that its + * entries be moved then this method fails (by throwing an {@code + * IOException}). To move a file tree may involve copying rather + * than moving directories and this can be done using the {@link + * #copy copy} method in conjunction with the {@link + * #walkFileTree Files.walkFileTree} utility method. + * + *

The {@code options} parameter may include any of the following: + * + * + * + * + * + * + * + * + * + * + *
Option Description
{@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} If the target file exists, then the target file is replaced if it + * is not a non-empty directory. If the target file exists and is a + * symbolic link, then the symbolic link itself, not the target of + * the link, is replaced.
{@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} The move is performed as an atomic file system operation and all + * other options are ignored. If the target file exists then it is + * implementation specific if the existing file is replaced or this method + * fails by throwing an {@link IOException}. If the move cannot be + * performed as an atomic file system operation then {@link + * AtomicMoveNotSupportedException} is thrown. This can arise, for + * example, when the target location is on a different {@code FileStore} + * and would require that the file be copied, or target location is + * associated with a different provider to this object.
+ * + *

An implementation of this interface may support additional + * implementation specific options. + * + *

Where the move requires that the file be copied then the {@link + * BasicFileAttributes#lastModifiedTime last-modified-time} is copied to the + * new file. An implementation may also attempt to copy other file + * attributes but is not required to fail if the file attributes cannot be + * copied. When the move is performed as a non-atomic operation, and a {@code + * IOException} is thrown, then the state of the files is not defined. The + * original file and the target file may both exist, the target file may be + * incomplete or some of its file attributes may not been copied from the + * original file. + * + *

Usage Examples: + * Suppose we want to rename a file to "newname", keeping the file in the + * same directory: + *

+     *     Path source = ...
+     *     Files.move(source, source.resolveSibling("newname"));
+     * 
+ * Alternatively, suppose we want to move a file to new directory, keeping + * the same file name, and replacing any existing file of that name in the + * directory: + *
+     *     Path source = ...
+     *     Path newdir = ...
+     *     Files.move(source, newdir.resolve(source.getFileName()), REPLACE_EXISTING);
+     * 
+ * + * @param source + * the path to the file to move + * @param target + * the path to the target file (may be associated with a different + * provider to the source path) + * @param options + * options specifying how the move should be done + * + * @return the path to the target file + * + * @throws UnsupportedOperationException + * if the array contains a copy option that is not supported + * @throws FileAlreadyExistsException + * if the target file exists but cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified (optional + * specific exception) + * @throws DirectoryNotEmptyException + * the {@code REPLACE_EXISTING} option is specified but the file + * cannot be replaced because it is a non-empty directory + * (optional specific exception) + * @throws AtomicMoveNotSupportedException + * if the options array contains the {@code ATOMIC_MOVE} option but + * the file cannot be moved as an atomic file system operation. + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to both the source and + * target file. + */ + public static Path move(Path source, Path target, CopyOption... options) + throws IOException + { + FileSystemProvider provider = provider(source); + if (provider(target) == provider) { + // same provider + provider.move(source, target, options); + } else { + // different providers + CopyMoveHelper.moveToForeignTarget(source, target, options); + } + return target; + } + + // -- Miscellenous -- + + /** + * Reads the target of a symbolic link (optional operation). + * + *

If the file system supports symbolic + * links then this method is used to read the target of the link, failing + * if the file is not a symbolic link. The target of the link need not exist. + * The returned {@code Path} object will be associated with the same file + * system as {@code link}. + * + * @param link + * the path to the symbolic link + * + * @return a {@code Path} object representing the target of the link + * + * @throws UnsupportedOperationException + * if the implementation does not support symbolic links + * @throws NotLinkException + * if the target could otherwise not be read because the file + * is not a symbolic link (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager + * is installed, it checks that {@code FilePermission} has been + * granted with the "{@code readlink}" action to read the link. + */ + public static Path readSymbolicLink(Path link) throws IOException { + return provider(link).readSymbolicLink(link); + } + + /** + * Returns the {@link FileStore} representing the file store where a file + * is located. + * + *

Once a reference to the {@code FileStore} is obtained it is + * implementation specific if operations on the returned {@code FileStore}, + * or {@link FileStoreAttributeView} objects obtained from it, continue + * to depend on the existence of the file. In particular the behavior is not + * defined for the case that the file is deleted or moved to a different + * file store. + * + * @param path + * the path to the file + * + * @return the file store where the file is stored + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file, and in + * addition it checks {@link RuntimePermission} + * ("getFileStoreAttributes") + */ + public static FileStore getFileStore(Path path) throws IOException { + return provider(path).getFileStore(path); + } + + /** + * Tests if two paths locate the same file. + * + *

If both {@code Path} objects are {@link Path#equals(Object) equal} + * then this method returns {@code true} without checking if the file exists. + * If the two {@code Path} objects are associated with different providers + * then this method returns {@code false}. Otherwise, this method checks if + * both {@code Path} objects locate the same file, and depending on the + * implementation, may require to open or access both files. + * + *

If the file system and files remain static, then this method implements + * an equivalence relation for non-null {@code Paths}. + *

    + *
  • It is reflexive: for {@code Path} {@code f}, + * {@code isSameFile(f,f)} should return {@code true}. + *
  • It is symmetric: for two {@code Paths} {@code f} and {@code g}, + * {@code isSameFile(f,g)} will equal {@code isSameFile(g,f)}. + *
  • It is transitive: for three {@code Paths} + * {@code f}, {@code g}, and {@code h}, if {@code isSameFile(f,g)} returns + * {@code true} and {@code isSameFile(g,h)} returns {@code true}, then + * {@code isSameFile(g,h)} will return return {@code true}. + *
+ * + * @param path + * one path to the file + * @param path2 + * the other path + * + * @return {@code true} if, and only if, the two paths locate the same file + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to both files. + * + * @see java.nio.file.attribute.BasicFileAttributes#fileKey + */ + public static boolean isSameFile(Path path, Path path2) throws IOException { + return provider(path).isSameFile(path, path2); + } + + /** + * Tells whether or not a file is considered hidden. The exact + * definition of hidden is platform or provider dependent. On UNIX for + * example a file is considered to be hidden if its name begins with a + * period character ('.'). On Windows a file is considered hidden if it + * isn't a directory and the DOS {@link DosFileAttributes#isHidden hidden} + * attribute is set. + * + *

Depending on the implementation this method may require to access + * the file system to determine if the file is considered hidden. + * + * @param path + * the path to the file to test + * + * @return {@code true} if the file is considered hidden + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + public static boolean isHidden(Path path) throws IOException { + return provider(path).isHidden(path); + } + + // lazy loading of default and installed file type detectors + private static class FileTypeDetectors{ + static final FileTypeDetector defaultFileTypeDetector = + sun.nio.fs.DefaultFileTypeDetector.create(); + static final List installeDetectors = + loadInstalledDetectors(); + + // loads all installed file type detectors + private static List loadInstalledDetectors() { + return AccessController + .doPrivileged(new PrivilegedAction>() { + @Override public List run() { + List list = new ArrayList<>(); + ServiceLoader loader = ServiceLoader + .load(FileTypeDetector.class, ClassLoader.getSystemClassLoader()); + for (FileTypeDetector detector: loader) { + list.add(detector); + } + return list; + }}); + } + } + + /** + * Probes the content type of a file. + * + *

This method uses the installed {@link FileTypeDetector} implementations + * to probe the given file to determine its content type. Each file type + * detector's {@link FileTypeDetector#probeContentType probeContentType} is + * invoked, in turn, to probe the file type. If the file is recognized then + * the content type is returned. If the file is not recognized by any of the + * installed file type detectors then a system-default file type detector is + * invoked to guess the content type. + * + *

A given invocation of the Java virtual machine maintains a system-wide + * list of file type detectors. Installed file type detectors are loaded + * using the service-provider loading facility defined by the {@link ServiceLoader} + * class. Installed file type detectors are loaded using the system class + * loader. If the system class loader cannot be found then the extension class + * loader is used; If the extension class loader cannot be found then the + * bootstrap class loader is used. File type detectors are typically installed + * by placing them in a JAR file on the application class path or in the + * extension directory, the JAR file contains a provider-configuration file + * named {@code java.nio.file.spi.FileTypeDetector} in the resource directory + * {@code META-INF/services}, and the file lists one or more fully-qualified + * names of concrete subclass of {@code FileTypeDetector } that have a zero + * argument constructor. If the process of locating or instantiating the + * installed file type detectors fails then an unspecified error is thrown. + * The ordering that installed providers are located is implementation + * specific. + * + *

The return value of this method is the string form of the value of a + * Multipurpose Internet Mail Extension (MIME) content type as + * defined by RFC 2045: + * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet + * Message Bodies. The string is guaranteed to be parsable according + * to the grammar in the RFC. + * + * @param path + * the path to the file to probe + * + * @return The content type of the file, or {@code null} if the content + * type cannot be determined + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * If a security manager is installed and it denies an unspecified + * permission required by a file type detector implementation. + */ + public static String probeContentType(Path path) + throws IOException + { + // try installed file type detectors + for (FileTypeDetector detector: FileTypeDetectors.installeDetectors) { + String result = detector.probeContentType(path); + if (result != null) + return result; + } + + // fallback to default + return FileTypeDetectors.defaultFileTypeDetector.probeContentType(path); + } + + // -- File Attributes -- + + /** + * Returns a file attribute view of a given type. + * + *

A file attribute view provides a read-only or updatable view of a + * set of file attributes. This method is intended to be used where the file + * attribute view defines type-safe methods to read or update the file + * attributes. The {@code type} parameter is the type of the attribute view + * required and the method returns an instance of that type if supported. + * The {@link BasicFileAttributeView} type supports access to the basic + * attributes of a file. Invoking this method to select a file attribute + * view of that type will always return an instance of that class. + * + *

The {@code options} array may be used to indicate how symbolic links + * are handled by the resulting file attribute view for the case that the + * file is a symbolic link. By default, symbolic links are followed. If the + * option {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} is present then + * symbolic links are not followed. This option is ignored by implementations + * that do not support symbolic links. + * + *

Usage Example: + * Suppose we want read or set a file's ACL, if supported: + *

+     *     Path path = ...
+     *     AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class);
+     *     if (view != null) {
+     *         List<AclEntry> acl = view.getAcl();
+     *         :
+     *     }
+     * 
+ * + * + * @param path + * the path to the file + * @param type + * the {@code Class} object corresponding to the file attribute view + * @param options + * options indicating how symbolic links are handled + * + * @return a file attribute view of the specified type, or {@code null} if + * the attribute view type is not available + */ + public static V getFileAttributeView(Path path, + Class type, + LinkOption... options) + { + return provider(path).getFileAttributeView(path, type, options); + } + + /** + * Reads a file's attributes as a bulk operation. + * + *

The {@code type} parameter is the type of the attributes required + * and this method returns an instance of that type if supported. All + * implementations support a basic set of file attributes and so invoking + * this method with a {@code type} parameter of {@code + * BasicFileAttributes.class} will not throw {@code + * UnsupportedOperationException}. + * + *

The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + *

It is implementation specific if all file attributes are read as an + * atomic operation with respect to other file system operations. + * + *

Usage Example: + * Suppose we want to read a file's attributes in bulk: + *

+     *    Path path = ...
+     *    BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
+     * 
+ * Alternatively, suppose we want to read file's POSIX attributes without + * following symbolic links: + *
+     *    PosixFileAttributes attrs = Files.readAttributes(path, PosixFileAttributes.class, NOFOLLOW_LINKS);
+     * 
+ * + * @param path + * the path to the file + * @param type + * the {@code Class} of the file attributes required + * to read + * @param options + * options indicating how symbolic links are handled + * + * @return the file attributes + * + * @throws UnsupportedOperationException + * if an attributes of the given type are not supported + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. If this + * method is invoked to read security sensitive attributes then the + * security manager may be invoke to check for additional permissions. + */ + public static A readAttributes(Path path, + Class type, + LinkOption... options) + throws IOException + { + return provider(path).readAttributes(path, type, options); + } + + /** + * Sets the value of a file attribute. + * + *

The {@code attribute} parameter identifies the attribute to be set + * and takes the form: + *

+ * [view-name:]attribute-name + *
+ * where square brackets [...] delineate an optional component and the + * character {@code ':'} stands for itself. + * + *

view-name is the {@link FileAttributeView#name name} of a {@link + * FileAttributeView} that identifies a set of file attributes. If not + * specified then it defaults to {@code "basic"}, the name of the file + * attribute view that identifies the basic set of file attributes common to + * many file systems. attribute-name is the name of the attribute + * within the set. + * + *

The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is set. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + *

Usage Example: + * Suppose we want to set the DOS "hidden" attribute: + *

+     *    Path path = ...
+     *    Files.setAttribute(path, "dos:hidden", true);
+     * 
+ * + * @param path + * the path to the file + * @param attribute + * the attribute to set + * @param value + * the attribute value + * @param options + * options indicating how symbolic links are handled + * + * @return the {@code path} parameter + * + * @throws UnsupportedOperationException + * if the attribute view is not available or it does not support + * updating the attribute + * @throws IllegalArgumentException + * if the attribute value is of the correct type but has an + * inappropriate value + * @throws ClassCastException + * if the attribute value is not of the expected type or is a + * collection containing elements that are not of the expected + * type + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. If this method is invoked + * to set security sensitive attributes then the security manager + * may be invoked to check for additional permissions. + */ + public static Path setAttribute(Path path, String attribute, Object value, + LinkOption... options) + throws IOException + { + provider(path).setAttribute(path, attribute, value, options); + return path; + } + + /** + * Reads the value of a file attribute. + * + *

The {@code attribute} parameter identifies the attribute to be read + * and takes the form: + *

+ * [view-name:]attribute-name + *
+ * where square brackets [...] delineate an optional component and the + * character {@code ':'} stands for itself. + * + *

view-name is the {@link FileAttributeView#name name} of a {@link + * FileAttributeView} that identifies a set of file attributes. If not + * specified then it defaults to {@code "basic"}, the name of the file + * attribute view that identifies the basic set of file attributes common to + * many file systems. attribute-name is the name of the attribute. + * + *

The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + *

Usage Example: + * Suppose we require the user ID of the file owner on a system that + * supports a "{@code unix}" view: + *

+     *    Path path = ...
+     *    int uid = (Integer)Files.getAttribute(path, "unix:uid");
+     * 
+ * + * @param path + * the path to the file + * @param attribute + * the attribute to read + * @param options + * options indicating how symbolic links are handled + * + * @return the attribute value or {@code null} if the attribute view + * is not available or it does not support reading the attribute + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. If this method is invoked + * to read security sensitive attributes then the security manager + * may be invoked to check for additional permissions. + */ + public static Object getAttribute(Path path, String attribute, + LinkOption... options) + throws IOException + { + // only one attribute should be read + if (attribute.indexOf('*') >= 0 || attribute.indexOf(',') >= 0) + return null; + Map map = readAttributes(path, attribute, options); + String name; + int pos = attribute.indexOf(':'); + if (pos == -1) { + name = attribute; + } else { + name = (pos == attribute.length()) ? "" : attribute.substring(pos+1); + } + return map.get(name); + } + + /** + * Reads a set of file attributes as a bulk operation. + * + *

The {@code attributes} parameter identifies the attributes to be read + * and takes the form: + *

+ * [view-name:]attribute-list + *
+ * where square brackets [...] delineate an optional component and the + * character {@code ':'} stands for itself. + * + *

view-name is the {@link FileAttributeView#name name} of a {@link + * FileAttributeView} that identifies a set of file attributes. If not + * specified then it defaults to {@code "basic"}, the name of the file + * attribute view that identifies the basic set of file attributes common to + * many file systems. + * + *

The attribute-list component is a comma separated list of + * zero or more names of attributes to read. If the list contains the value + * {@code "*"} then all attributes are read. Attributes that are not supported + * are ignored and will not be present in the returned map. It is + * implementation specific if all attributes are read as an atomic operation + * with respect to other file system operations. + * + *

The following examples demonstrate possible values for the {@code + * attributes} parameter: + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@code "*"} Read all {@link BasicFileAttributes basic-file-attributes}.
{@code "size,lastModifiedTime,lastAccessTime"} Reads the file size, last modified time, and last access time + * attributes.
{@code "posix:*"} Read all {@link PosixFileAttributes POSIX-file-attributes}.
{@code "posix:permissions,owner,size"} Reads the POSX file permissions, owner, and file size.
+ *
+ * + *

The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + * @param path + * the path to the file + * @param attributes + * the attributes to read + * @param options + * options indicating how symbolic links are handled + * + * @return a map of the attributes returned; may be empty. The map's keys + * are the attribute names, its values are the attribute values + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. If this method is invoked + * to read security sensitive attributes then the security manager + * may be invoke to check for additional permissions. + */ + public static Map readAttributes(Path path, String attributes, + LinkOption... options) + throws IOException + { + return provider(path).readAttributes(path, attributes, options); + } + + /** + * Returns a file's POSIX file permissions. + * + *

The {@code path} parameter is associated with a {@code FileSystem} + * that supports the {@link PosixFileAttributeView}. This attribute view + * provides access to file attributes commonly associated with files on file + * systems used by operating systems that implement the Portable Operating + * System Interface (POSIX) family of standards. + * + *

The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + * @param path + * the path to the file + * @param options + * options indicating how symbolic links are handled + * + * @return the file permissions + * + * @throws UnsupportedOperationException + * if the associated file system does not support the {@code + * PosixFileAttributeView} + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, and it denies {@link RuntimePermission}("accessUserInformation") + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + */ + public static Set getPosixFilePermissions(Path path, + LinkOption... options) + throws IOException + { + return readAttributes(path, PosixFileAttributes.class, options).permissions(); + } + + /** + * Sets a file's POSIX permissions. + * + *

The {@code path} parameter is associated with a {@code FileSystem} + * that supports the {@link PosixFileAttributeView}. This attribute view + * provides access to file attributes commonly associated with files on file + * systems used by operating systems that implement the Portable Operating + * System Interface (POSIX) family of standards. + * + * @param path + * A file reference that locates the file + * @param perms + * The new set of permissions + * + * @throws UnsupportedOperationException + * if the associated file system does not support the {@code + * PosixFileAttributeView} + * @throws ClassCastException + * if the sets contains elements that are not of type {@code + * PosixFilePermission} + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}("accessUserInformation") + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + */ + public static Path setPosixFilePermissions(Path path, + Set perms) + throws IOException + { + PosixFileAttributeView view = + getFileAttributeView(path, PosixFileAttributeView.class); + if (view == null) + throw new UnsupportedOperationException(); + view.setPermissions(perms); + return path; + } + + /** + * Returns the owner of a file. + * + *

The {@code path} parameter is associated with a file system that + * supports {@link FileOwnerAttributeView}. This file attribute view provides + * access to a file attribute that is the owner of the file. + * + * @param path + * A file reference that locates the file + * @param options + * options indicating how symbolic links are handled + * + * @return A user principal representing the owner of the file + * + * @throws UnsupportedOperationException + * if the associated file system does not support the {@code + * FileOwnerAttributeView} + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}("accessUserInformation") + * or its {@link SecurityManager#checkRead(String) checkRead} method + * denies read access to the file. + */ + public static UserPrincipal getOwner(Path path, LinkOption... options) throws IOException { + FileOwnerAttributeView view = + getFileAttributeView(path, FileOwnerAttributeView.class, options); + if (view == null) + throw new UnsupportedOperationException(); + return view.getOwner(); + } + + /** + * Updates the file owner. + * + *

The {@code path} parameter is associated with a file system that + * supports {@link FileOwnerAttributeView}. This file attribute view provides + * access to a file attribute that is the owner of the file. + * + *

Usage Example: + * Suppose we want to make "joe" the owner of a file: + *

+     *     Path path = ...
+     *     UserPrincipalLookupService lookupService =
+     *         provider(path).getUserPrincipalLookupService();
+     *     UserPrincipal joe = lookupService.lookupPrincipalByName("joe");
+     *     Files.setOwner(path, joe);
+     * 
+ * + * @param path + * A file reference that locates the file + * @param owner + * The new file owner + * + * @throws UnsupportedOperationException + * if the associated file system does not support the {@code + * FileOwnerAttributeView} + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, it denies {@link RuntimePermission}("accessUserInformation") + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. + * + * @see FileSystem#getUserPrincipalLookupService + * @see java.nio.file.attribute.UserPrincipalLookupService + */ + public static Path setOwner(Path path, UserPrincipal owner) + throws IOException + { + FileOwnerAttributeView view = + getFileAttributeView(path, FileOwnerAttributeView.class); + if (view == null) + throw new UnsupportedOperationException(); + view.setOwner(owner); + return path; + } + + /** + * Tests whether a file is a symbolic link. + * + *

Where is it required to distinguish an I/O exception from the case + * that the file is not a symbolic link then the file attributes can be + * read with the {@link #readAttributes(Path,Class,LinkOption[]) + * readAttributes} method and the file type tested with the {@link + * BasicFileAttributes#isSymbolicLink} method. + * + * @return {@code true} if the file is a symbolic link; {@code false} if + * the file does not exist, is not a symbolic link, or it cannot + * be determined if the file is symbolic link or not. + * + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. + */ + public static boolean isSymbolicLink(Path path) { + try { + return readAttributes(path, + BasicFileAttributes.class, + LinkOption.NOFOLLOW_LINKS).isSymbolicLink(); + } catch (IOException ioe) { + return false; + } + } + + /** + * Tests whether a file is a directory. + * + *

The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + *

Where is it required to distinguish an I/O exception from the case + * that the file is not a directory then the file attributes can be + * read with the {@link #readAttributes(Path,Class,LinkOption[]) + * readAttributes} method and the file type tested with the {@link + * BasicFileAttributes#isDirectory} method. + * + * @param path + * the path to the file to test + * @param options + * options indicating how symbolic links are handled + * + * @return {@code true} if the file is a directory; {@code false} if + * the file does not exist, is not a directory, or it cannot + * be determined if the file is directory or not. + * + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. + */ + public static boolean isDirectory(Path path, LinkOption... options) { + try { + return readAttributes(path, BasicFileAttributes.class, options).isDirectory(); + } catch (IOException ioe) { + return false; + } + } + + /** + * Tests whether a file is a regular file with opaque content. + * + *

The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + *

Where is it required to distinguish an I/O exception from the case + * that the file is not a regular file then the file attributes can be + * read with the {@link #readAttributes(Path,Class,LinkOption[]) + * readAttributes} method and the file type tested with the {@link + * BasicFileAttributes#isRegularFile} method. + * + * @param path + * the path to the file + * @param options + * options indicating how symbolic links are handled + * + * @return {@code true} if the file is a regular file; {@code false} if + * the file does not exist, is not a direcregular filetory, or it + * cannot be determined if the file is regular file or not. + * + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. + */ + public static boolean isRegularFile(Path path, LinkOption... options) { + try { + return readAttributes(path, BasicFileAttributes.class, options).isRegularFile(); + } catch (IOException ioe) { + return false; + } + } + + /** + * Returns a file's last modified time. + * + *

The {@code options} array may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed and the file attribute of the final target + * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + * @param path + * the path to the file + * @param options + * options indicating how symbolic links are handled + * + * @return a {@code FileTime} representing the time the file was last + * modified, or an implementation specific default when a time + * stamp to indicate the time of last modification is not supported + * by the file system + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. + * + * @see BasicFileAttributes#lastModifiedTime + */ + public static FileTime getLastModifiedTime(Path path, LinkOption... options) + throws IOException + { + return readAttributes(path, BasicFileAttributes.class, options).lastModifiedTime(); + } + + /** + * Updates a file's last modified time attribute. The file time is converted + * to the epoch and precision supported by the file system. Converting from + * finer to coarser granularities result in precision loss. The behavior of + * this method when attempting to set the last modified time when it is not + * supported by the file system or is outside the range supported by the + * underlying file store is not defined. It may or not fail by throwing an + * {@code IOException}. + * + *

Usage Example: + * Suppose we want to set the last modified time to the current time: + *

+     *    Path path = ...
+     *    FileTime now = FileTime.fromMillis(System.currentTimeMillis());
+     *    Files.setLastModifiedTime(path, now);
+     * 
+ * + * @param path + * the path to the file + * @param time + * the new last modified time + * + * @return the file + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, the security manager's {@link + * SecurityManager#checkWrite(String) checkWrite} method is invoked + * to check write access to file + * + * @see BasicFileAttributeView#setTimes + */ + public static Path setLastModifiedTime(Path path, FileTime time) + throws IOException + { + getFileAttributeView(path, BasicFileAttributeView.class) + .setTimes(time, null, null); + return path; + } + + /** + * Returns the size of a file (in bytes). The size may differ from the + * actual size on the file system due to compression, support for sparse + * files, or other reasons. The size of files that are not {@link + * #isRegularFile regular} files is implementation specific and + * therefore unspecified. + * + * @param path + * the path to the file + * + * @return the file size, in bytes + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. + * + * @see BasicFileAttributes#size + */ + public static long size(Path path) throws IOException { + return readAttributes(path, BasicFileAttributes.class).size(); + } + + // -- Accessibility -- + + /** + * Returns {@code false} if NOFOLLOW_LINKS is present. + */ + private static boolean followLinks(LinkOption... options) { + boolean followLinks = true; + for (LinkOption opt: options) { + if (opt == LinkOption.NOFOLLOW_LINKS) { + followLinks = false; + continue; + } + if (opt == null) + throw new NullPointerException(); + throw new AssertionError("Should not get here"); + } + return followLinks; + } + + /** + * Tests whether a file exists. + * + *

The {@code options} parameter may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + *

Note that the result of this method is immediately outdated. If this + * method indicates the file exists then there is no guarantee that a + * subsequence access will succeed. Care should be taken when using this + * method in security sensitive applications. + * + * @param path + * the path to the file to test + * @param options + * options indicating how symbolic links are handled + * . + * @return {@code true} if the file exists; {@code false} if the file does + * not exist or its existence cannot be determined. + * + * @throws SecurityException + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} is invoked to check + * read access to the file. + * + * @see #notExists + */ + public static boolean exists(Path path, LinkOption... options) { + try { + if (followLinks(options)) { + provider(path).checkAccess(path); + } else { + // attempt to read attributes without following links + readAttributes(path, BasicFileAttributes.class, + LinkOption.NOFOLLOW_LINKS); + } + // file exists + return true; + } catch (IOException x) { + // does not exist or unable to determine if file exists + return false; + } + + } + + /** + * Tests whether the file located by this path does not exist. This method + * is intended for cases where it is required to take action when it can be + * confirmed that a file does not exist. + * + *

The {@code options} parameter may be used to indicate how symbolic links + * are handled for the case that the file is a symbolic link. By default, + * symbolic links are followed. If the option {@link LinkOption#NOFOLLOW_LINKS + * NOFOLLOW_LINKS} is present then symbolic links are not followed. + * + *

Note that this method is not the complement of the {@link #exists + * exists} method. Where it is not possible to determine if a file exists + * or not then both methods return {@code false}. As with the {@code exists} + * method, the result of this method is immediately outdated. If this + * method indicates the file does exist then there is no guarantee that a + * subsequence attempt to create the file will succeed. Care should be taken + * when using this method in security sensitive applications. + * + * @param path + * the path to the file to test + * @param options + * options indicating how symbolic links are handled + * + * @return {@code true} if the file does not exist; {@code false} if the + * file exists or its existence cannot be determined + * + * @throws SecurityException + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String)} is invoked to check + * read access to the file. + */ + public static boolean notExists(Path path, LinkOption... options) { + try { + if (followLinks(options)) { + provider(path).checkAccess(path); + } else { + // attempt to read attributes without following links + readAttributes(path, BasicFileAttributes.class, + LinkOption.NOFOLLOW_LINKS); + } + // file exists + return false; + } catch (NoSuchFileException x) { + // file confirmed not to exist + return true; + } catch (IOException x) { + return false; } } /** - * Probes the content type of a file. + * Used by isReadbale, isWritable, isExecutable to test access to a file. + */ + private static boolean isAccessible(Path path, AccessMode... modes) { + try { + provider(path).checkAccess(path, modes); + return true; + } catch (IOException x) { + return false; + } + } + + /** + * Tests whether a file is readable. This method checks that a file exists + * and that this Java virtual machine has appropriate privileges that would + * allow it open the file for reading. Depending on the implementation, this + * method may require to read file permissions, access control lists, or + * other file attributes in order to check the effective access to the file. + * Consequently, this method may not be atomic with respect to other file + * system operations. * - *

This method uses the installed {@link FileTypeDetector} implementations - * to probe the given file to determine its content type. Each file type - * detector's {@link FileTypeDetector#probeContentType probeContentType} is - * invoked, in turn, to probe the file type. If the file is recognized then - * the content type is returned. If the file is not recognized by any of the - * installed file type detectors then a system-default file type detector is - * invoked to guess the content type. + *

Note that the result of this method is immediately outdated, there is + * no guarantee that a subsequent attempt to open the file for reading will + * succeed (or even that it will access the same file). Care should be taken + * when using this method in security sensitive applications. * - *

A given invocation of the Java virtual machine maintains a system-wide - * list of file type detectors. Installed file type detectors are loaded - * using the service-provider loading facility defined by the {@link ServiceLoader} - * class. Installed file type detectors are loaded using the system class - * loader. If the system class loader cannot be found then the extension class - * loader is used; If the extension class loader cannot be found then the - * bootstrap class loader is used. File type detectors are typically installed - * by placing them in a JAR file on the application class path or in the - * extension directory, the JAR file contains a provider-configuration file - * named {@code java.nio.file.spi.FileTypeDetector} in the resource directory - * {@code META-INF/services}, and the file lists one or more fully-qualified - * names of concrete subclass of {@code FileTypeDetector } that have a zero - * argument constructor. If the process of locating or instantiating the - * installed file type detectors fails then an unspecified error is thrown. - * The ordering that installed providers are located is implementation - * specific. + * @param path + * the path to the file to check * - *

The return value of this method is the string form of the value of a - * Multipurpose Internet Mail Extension (MIME) content type as - * defined by RFC 2045: - * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet - * Message Bodies. The string is guaranteed to be parsable according - * to the grammar in the RFC. + * @return {@code true} if the file exists and is readable; {@code false} + * if the file does not exist, read access would be denied because + * the Java virtual machine has insufficient privileges, or access + * cannot be determined + * + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * is invoked to check read access to the file. + */ + public static boolean isReadable(Path path) { + return isAccessible(path, AccessMode.READ); + } + + /** + * Tests whether a file is writable. This method checks that a file exists + * and that this Java virtual machine has appropriate privileges that would + * allow it open the file for writing. Depending on the implementation, this + * method may require to read file permissions, access control lists, or + * other file attributes in order to check the effective access to the file. + * Consequently, this method may not be atomic with respect to other file + * system operations. * - * @param file - * The file reference + *

Note that result of this method is immediately outdated, there is no + * guarantee that a subsequent attempt to open the file for writing will + * succeed (or even that it will access the same file). Care should be taken + * when using this method in security sensitive applications. * - * @return The content type of the file, or {@code null} if the content - * type cannot be determined + * @param path + * the path to the file to check + * + * @return {@code true} if the file exists and is writable; {@code false} + * if the file does not exist, write access would be denied because + * the Java virtual machine has insufficient privileges, or access + * cannot be determined * - * @throws IOException - * If an I/O error occurs * @throws SecurityException - * If a security manager is installed and it denies an unspecified - * permission required by a file type detector implementation. + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * is invoked to check write access to the file. */ - public static String probeContentType(FileRef file) - throws IOException - { - // try installed file type detectors - for (FileTypeDetector detector: DefaultFileTypeDetectorHolder.installeDetectors) { - String result = detector.probeContentType(file); - if (result != null) - return result; - } + public static boolean isWritable(Path path) { + return isAccessible(path, AccessMode.WRITE); + } - // fallback to default - return DefaultFileTypeDetectorHolder.defaultFileTypeDetector - .probeContentType(file); + /** + * Tests whether a file is executable. This method checks that a file exists + * and that this Java virtual machine has appropriate privileges to {@link + * Runtime#exec execute} the file. The semantics may differ when checking + * access to a directory. For example, on UNIX systems, checking for + * execute access checks that the Java virtual machine has permission to + * search the directory in order to access file or subdirectories. + * + *

Depending on the implementation, this method may require to read file + * permissions, access control lists, or other file attributes in order to + * check the effective access to the file. Consequently, this method may not + * be atomic with respect to other file system operations. + * + *

Note that the result of this method is immediately outdated, there is + * no guarantee that a subsequent attempt to execute the file will succeed + * (or even that it will access the same file). Care should be taken when + * using this method in security sensitive applications. + * + * @param path + * the path to the file to check + * + * @return {@code true} if the file exists and is executable; {@code false} + * if the file does not exist, execute access would be denied because + * the Java virtual machine has insufficient privileges, or access + * cannot be determined + * + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkExec(String) + * checkExec} is invoked to check execute access to the file. + */ + public static boolean isExecutable(Path path) { + return isAccessible(path, AccessMode.EXECUTE); } + // -- Recursive operations -- + /** * Walks a file tree. * @@ -139,7 +2484,7 @@ public final class Files { * an uncaught error, or runtime exception, then the traversal is terminated * and the error or exception is propagated to the caller of this method. * - *

For each file encountered this method attempts to gets its {@link + *

For each file encountered this method attempts to read its {@link * java.nio.file.attribute.BasicFileAttributes}. If the file is not a * directory then the {@link FileVisitor#visitFile visitFile} method is * invoked with the file attributes. If the file attributes cannot be read, @@ -174,7 +2519,7 @@ public final class Files { * arises when there is an entry in a directory that is an ancestor of the * directory. Cycle detection is done by recording the {@link * java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories, - * or if file keys are not available, by invoking the {@link Path#isSameFile + * or if file keys are not available, by invoking the {@link #isSameFile * isSameFile} method to test if a directory is the same file as an * ancestor. When a cycle is detected it is treated as an I/O error, and the * {@link FileVisitor#visitFileFailed visitFileFailed} method is invoked with @@ -197,25 +2542,27 @@ public final class Files { * that file (or directory). * * @param start - * The starting file + * the starting file * @param options - * Options to configure the traversal + * options to configure the traversal * @param maxDepth - * The maximum number of directory levels to visit + * the maximum number of directory levels to visit * @param visitor - * The file visitor to invoke for each file + * the file visitor to invoke for each file + * + * @return the starting file * * @throws IllegalArgumentException - * If the {@code maxDepth} parameter is negative + * if the {@code maxDepth} parameter is negative * @throws SecurityException * If the security manager denies access to the starting file. * In the case of the default provider, the {@link * SecurityManager#checkRead(String) checkRead} method is invoked * to check read access to the directory. * @throws IOException - * If an I/O error is thrown by a visitor method + * if an I/O error is thrown by a visitor method */ - public static void walkFileTree(Path start, + public static Path walkFileTree(Path start, Set options, int maxDepth, FileVisitor visitor) @@ -224,6 +2571,7 @@ public final class Files { if (maxDepth < 0) throw new IllegalArgumentException("'maxDepth' is negative"); new FileTreeWalker(options, visitor, maxDepth).walk(start); + return start; } /** @@ -234,11 +2582,15 @@ public final class Files { *

      * walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, visitor)
      * 
+ * In other words, it does not follow symbolic links, and visits all levels + * of the file level. * * @param start - * The starting file + * the starting file * @param visitor - * The file visitor to invoke for each file + * the file visitor to invoke for each file + * + * @return the starting file * * @throws SecurityException * If the security manager denies access to the starting file. @@ -246,118 +2598,511 @@ public final class Files { * SecurityManager#checkRead(String) checkRead} method is invoked * to check read access to the directory. * @throws IOException - * If an I/O error is thrown by a visitor method + * if an I/O error is thrown by a visitor method */ - public static void walkFileTree(Path start, FileVisitor visitor) + public static Path walkFileTree(Path start, FileVisitor visitor) throws IOException { - walkFileTree(start, - EnumSet.noneOf(FileVisitOption.class), - Integer.MAX_VALUE, - visitor); + return walkFileTree(start, + EnumSet.noneOf(FileVisitOption.class), + Integer.MAX_VALUE, + visitor); } + + // -- Utility methods for simple usages -- + + // buffer size used for reading and writing + private static final int BUFFER_SIZE = 8192; + /** - * Creates a directory by creating all nonexistent parent directories first. + * Opens a file for reading, returning a {@code BufferedReader} that may be + * used to read text from the file in an efficient manner. Bytes from the + * file are decoded into characters using the specified charset. Reading + * commences at the beginning of the file. * - *

The {@code attrs} parameter is an optional array of {@link FileAttribute - * file-attributes} to set atomically when creating the nonexistent - * directories. Each file attribute is identified by its {@link - * FileAttribute#name name}. If more than one attribute of the same name is - * included in the array then all but the last occurrence is ignored. + *

The {@code Reader} methods that read from the file throw {@code + * IOException} if a malformed or unmappable byte sequence is read. * - *

If this method fails, then it may do so after creating some, but not - * all, of the parent directories. + * @param path + * the path to the file + * @param cs + * the charset to use for decoding * - * @param dir - * the directory to create + * @return a new buffered reader, with default buffer size, to read text + * from the file * - * @param attrs - * an optional list of file attributes to set atomically when - * creating the directory + * @throws IOException + * if an I/O error occurs opening the file + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + * + * @see #readAllLines + */ + public static BufferedReader newBufferedReader(Path path, Charset cs) + throws IOException + { + CharsetDecoder decoder = cs.newDecoder(); + Reader reader = new InputStreamReader(newInputStream(path), decoder); + return new BufferedReader(reader); + } + + /** + * Opens or creates a file for writing, returning a {@code BufferedWriter} + * that may be used to write text to the file in an efficient manner. + * The {@code options} parameter specifies how the the file is created or + * opened. If no options are present then this method works as if the {@link + * StandardOpenOption#CREATE CREATE}, {@link + * StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING}, and {@link + * StandardOpenOption#WRITE WRITE} options are present. In other words, it + * opens the file for writing, creating the file if it doesn't exist, or + * initially truncating an existing {@link #isRegularFile regular-file} to + * a size of {@code 0} if it exists. + * + *

The {@code Writer} methods to write text throw {@code IOException} + * if the text cannot be encoded using the specified charset. + * + * @param path + * the path to the file + * @param cs + * the charset to use for encoding + * @param options + * options specifying how the file is opened + * + * @return a new buffered writer, with default buffer size, to write text + * to the file * - * @throws UnsupportedOperationException - * if the array contains an attribute that cannot be set atomically - * when creating the directory - * @throws FileAlreadyExistsException - * if {@code dir} exists but is not a directory (optional specific - * exception) * @throws IOException - * if an I/O error occurs + * if an I/O error occurs opening or creating the file + * @throws UnsupportedOperationException + * if an unsupported option is specified * @throws SecurityException - * in the case of the default provider, and a security manager is + * In the case of the default provider, and a security manager is * installed, the {@link SecurityManager#checkWrite(String) checkWrite} - * method is invoked prior to attempting to create a directory and - * its {@link SecurityManager#checkRead(String) checkRead} is - * invoked for each parent directory that is checked. If {@code - * dir} is not an absolute path then its {@link Path#toAbsolutePath - * toAbsolutePath} may need to be invoked to get its absolute path. - * This may invoke the security manager's {@link - * SecurityManager#checkPropertyAccess(String) checkPropertyAccess} - * method to check access to the system property {@code user.dir} + * method is invoked to check write access to the file. * + * @see #write(Path,Iterable,Charset,OpenOption[]) */ - public static void createDirectories(Path dir, FileAttribute... attrs) + public static BufferedWriter newBufferedWriter(Path path, Charset cs, + OpenOption... options) throws IOException { - // attempt to create the directory - try { - createAndCheckIsDirectory(dir, attrs); - return; - } catch (FileAlreadyExistsException x) { - // file exists and is not a directory - throw x; - } catch (IOException x) { - // parent may not exist or other reason + CharsetEncoder encoder = cs.newEncoder(); + Writer writer = new OutputStreamWriter(newOutputStream(path, options), encoder); + return new BufferedWriter(writer); + } + + /** + * Reads all bytes from an input stream and writes them to an output stream. + */ + private static long copy(InputStream source, OutputStream sink) + throws IOException + { + long nread = 0L; + byte[] buf = new byte[BUFFER_SIZE]; + int n; + while ((n = source.read(buf)) > 0) { + sink.write(buf, 0, n); + nread += n; } + return nread; + } - // find existing parent (may require absolute path) - SecurityException se = null; - try { - dir = dir.toAbsolutePath(); - } catch (SecurityException x) { - // don't have permission to get absolute path - se = x; + /** + * Copies all bytes from an input stream to a file. On return, the input + * stream will be at end of stream. + * + *

By default, the copy fails if the target file already exists or is a + * symbolic link. If the {@link StandardCopyOption#REPLACE_EXISTING + * REPLACE_EXISTING} option is specified, and the target file already exists, + * then it is replaced if it is not a non-empty directory. If the target + * file exists and is a symbolic link, then the symbolic link is replaced. + * In this release, the {@code REPLACE_EXISTING} option is the only option + * required to be supported by this method. Additional options may be + * supported in future releases. + * + *

If an I/O error occurs reading from the input stream or writing to + * the file, then it may do so after the target file has been created and + * after some bytes have been read or written. Consequently the input + * stream may not be at end of stream and may be in an inconsistent state. + * It is strongly recommended that the input stream be promptly closed if an + * I/O error occurs. + * + *

This method may block indefinitely reading from the input stream (or + * writing to the file). The behavior for the case that the input stream is + * asynchronously closed or the thread interrupted during the copy is + * highly input stream and file system provider specific and therefore not + * specified. + * + *

Usage example: Suppose we want to capture a web page and save + * it to a file: + *

+     *     Path path = ...
+     *     URI u = URI.create("http://java.sun.com/");
+     *     try (InputStream in = u.toURL().openStream()) {
+     *         Files.copy(in, path);
+     *     }
+     * 
+ * + * @param in + * the input stream to read from + * @param target + * the path to the file + * @param options + * options specifying how the copy should be done + * + * @return the number of bytes read or written + * + * @throws IOException + * if an I/O error occurs when reading or writing + * @throws FileAlreadyExistsException + * if the target file exists but cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified (optional + * specific exception) + * @throws DirectoryNotEmptyException + * the {@code REPLACE_EXISTING} option is specified but the file + * cannot be replaced because it is a non-empty directory + * (optional specific exception) * + * @throws UnsupportedOperationException + * if {@code options} contains a copy option that is not supported + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. Where the + * {@code REPLACE_EXISTING} option is specified, the security + * manager's {@link SecurityManager#checkDelete(String) checkDelete} + * method is invoked to check that an existing file can be deleted. + */ + public static long copy(InputStream in, Path target, CopyOption... options) + throws IOException + { + // ensure not null before opening file + Objects.nonNull(in); + + // check for REPLACE_EXISTING + boolean replaceExisting = false; + for (CopyOption opt: options) { + if (opt == StandardCopyOption.REPLACE_EXISTING) { + replaceExisting = true; + } else { + if (opt == null) { + throw new NullPointerException("options contains 'null'"); + } else { + throw new UnsupportedOperationException(opt + " not supported"); + } + } } - Path parent = dir.getParent(); - while (parent != null) { + + // attempt to delete an existing file + SecurityException se = null; + if (replaceExisting) { try { - parent.checkAccess(); - break; - } catch (NoSuchFileException x) { - // does not exist + deleteIfExists(target); + } catch (SecurityException x) { + se = x; } - parent = parent.getParent(); } - if (parent == null) { - // unable to find existing parent + + // attempt to create target file. If it fails with + // FileAlreadyExistsException then it may be because the security + // manager prevented us from deleting the file, in which case we just + // throw the SecurityException. + OutputStream ostream; + try { + ostream = newOutputStream(target, StandardOpenOption.CREATE_NEW, + StandardOpenOption.WRITE); + } catch (FileAlreadyExistsException x) { if (se != null) throw se; - throw new IOException("Root directory does not exist"); + // someone else won the race and created the file + throw x; } - // create directories - Path child = parent; - for (Path name: parent.relativize(dir)) { - child = child.resolve(name); - createAndCheckIsDirectory(child, attrs); + // do the copy + try (OutputStream out = ostream) { + return copy(in, out); } } /** - * Attempts to create a directory. Does nothing if the directory already - * exists. + * Copies all bytes from a file to an output stream. + * + *

If an I/O error occurs reading from the file or writing to the output + * stream, then it may do so after some bytes have been read or written. + * Consequently the output stream may be in an inconsistent state. It is + * strongly recommended that the output stream be promptly closed if an I/O + * error occurs. + * + *

This method may block indefinitely writing to the output stream (or + * reading from the file). The behavior for the case that the output stream + * is asynchronously closed or the thread interrupted during the copy + * is highly output stream and file system provider specific and therefore + * not specified. + * + *

Note that if the given output stream is {@link java.io.Flushable} + * then its {@link java.io.Flushable#flush flush} method may need to invoked + * after this method completes so as to flush any buffered output. + * + * @param source + * the path to the file + * @param out + * the output stream to write to + * + * @return the number of bytes read or written + * + * @throws IOException + * if an I/O error occurs when reading or writing + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + public static long copy(Path source, OutputStream out) throws IOException { + // ensure not null before opening file + Objects.nonNull(out); + + try (InputStream in = newInputStream(source)) { + return copy(in, out); + } + } + + /** + * Read all the bytes from an input stream. The {@code initialSize} + * parameter indicates the initial size of the byte[] to allocate. */ - private static void createAndCheckIsDirectory(Path dir, FileAttribute... attrs) + private static byte[] read(InputStream source, int initialSize) throws IOException { - try { - dir.createDirectory(attrs); - } catch (FileAlreadyExistsException x) { - boolean isDirectory = Attributes - .readBasicFileAttributes(dir, LinkOption.NOFOLLOW_LINKS).isDirectory(); - if (!isDirectory) - throw x; + int capacity = initialSize; + byte[] buf = new byte[capacity]; + int nread = 0; + int rem = buf.length; + int n; + // read to EOF which may read more or less than initialSize (eg: file + // is truncated while we are reading) + while ((n = source.read(buf, nread, rem)) > 0) { + nread += n; + rem -= n; + assert rem >= 0; + if (rem == 0) { + // need larger buffer + int newCapacity = capacity << 1; + if (newCapacity < 0) { + if (capacity == Integer.MAX_VALUE) + throw new OutOfMemoryError("Required array size too large"); + newCapacity = Integer.MAX_VALUE; + } + rem = newCapacity - capacity; + buf = Arrays.copyOf(buf, newCapacity); + capacity = newCapacity; + } + } + return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); + } + + /** + * Read all the bytes from a file. The method ensures that the file is + * closed when all bytes have been read or an I/O error, or other runtime + * exception, is thrown. + * + *

Note that this method is intended for simple cases where it is + * convenient to read all bytes into a byte array. It is not intended for + * reading in large files. + * + * @param path + * the path to the file + * + * @return a byte array containing the bytes read from the file + * + * @throws IOException + * if an I/O error occurs reading from the stream + * @throws OutOfMemoryError + * if an array of the required size cannot be allocated, for + * example the file is larger that {@code 2GB} + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + public static byte[] readAllBytes(Path path) throws IOException { + long size = size(path); + if (size > (long)Integer.MAX_VALUE) + throw new OutOfMemoryError("Required array size too large"); + + try (InputStream in = newInputStream(path)) { + return read(in, (int)size); + } + } + + /** + * Read all lines from a file. This method ensures that the file is + * closed when all bytes have been read or an I/O error, or other runtime + * exception, is thrown. Bytes from the file are decoded into characters + * using the specified charset. + * + *

This method recognizes the following as line terminators: + *

    + *
  • \u000D followed by \u000A, + * CARRIAGE RETURN followed by LINE FEED
  • + *
  • \u000A, LINE FEED
  • + *
  • \u000D, CARRIAGE RETURN
  • + *
+ *

Additional Unicode line terminators may be recognized in future + * releases. + * + *

Note that this method is intended for simple cases where it is + * convenient to read all lines in a single operation. It is not intended + * for reading in large files. + * + * @param path + * the path to the file + * @param cs + * the charset to use for decoding + * + * @return the lines from the file as a {@code List}; whether the {@code + * List} is modifiable or not is implementation dependent and + * therefore not specified + * + * @throws IOException + * if an I/O error occurs reading from the file or a malformed or + * unmappable byte sequence is read + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + * + * @see #newBufferedReader + */ + public static List readAllLines(Path path, Charset cs) + throws IOException + { + try (BufferedReader reader = newBufferedReader(path, cs)) { + List result = new ArrayList<>(); + for (;;) { + String line = reader.readLine(); + if (line == null) + break; + result.add(line); + } + return result; + } + } + + /** + * Writes bytes to a file. The {@code options} parameter specifies how the + * the file is created or opened. If no options are present then this method + * works as if the {@link StandardOpenOption#CREATE CREATE}, {@link + * StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING}, and {@link + * StandardOpenOption#WRITE WRITE} options are present. In other words, it + * opens the file for writing, creating the file if it doesn't exist, or + * initially truncating an existing {@link #isRegularFile regular-file} to + * a size of {@code 0}. All bytes in the byte array are written to the file. + * The method ensures that the file is closed when all bytes have been + * written (or an I/O error or other runtime exception is thrown). If an I/O + * error occurs then it may do so after the file has created or truncated, + * or after some bytes have been written to the file. + * + *

Usage example: By default the method creates a new file or + * overrides an existing file. Suppose you instead want to append bytes + * to an existing file: + *

+     *     Path path = ...
+     *     byte[] bytes = ...
+     *     Files.write(path, bytes, StandardOpenOption.APPEND);
+     * 
+ * + * @param path + * the path to the file + * @param bytes + * the byte array with the bytes to write + * @param options + * options specifying how the file is opened + * + * @return the path + * + * @throws IOException + * if an I/O error occurs writing to or creating the file + * @throws UnsupportedOperationException + * if an unsupported option is specified + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. + */ + public static Path write(Path path, byte[] bytes, OpenOption... options) + throws IOException + { + // ensure bytes is not null before opening file + Objects.nonNull(bytes); + + try (OutputStream out = Files.newOutputStream(path, options)) { + int len = bytes.length; + int rem = len; + while (rem > 0) { + int n = Math.min(rem, BUFFER_SIZE); + out.write(bytes, (len-rem), n); + rem -= n; + } + } + return path; + } + + /** + * Write lines of text to a file. Each line is a char sequence and is + * written to the file in sequence with each line terminated by the + * platform's line separator, as defined by the system property {@code + * line.separator}. Characters are encoded into bytes using the specified + * charset. + * + *

The {@code options} parameter specifies how the the file is created + * or opened. If no options are present then this method works as if the + * {@link StandardOpenOption#CREATE CREATE}, {@link + * StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING}, and {@link + * StandardOpenOption#WRITE WRITE} options are present. In other words, it + * opens the file for writing, creating the file if it doesn't exist, or + * initially truncating an existing {@link #isRegularFile regular-file} to + * a size of {@code 0}. The method ensures that the file is closed when all + * lines have been written (or an I/O error or other runtime exception is + * thrown). If an I/O error occurs then it may do so after the file has + * created or truncated, or after some bytes have been written to the file. + * + * @param path + * the path to the file + * @param lines + * an object to iterate over the char sequences + * @param cs + * the charset to use for encoding + * @param options + * options specifying how the file is opened + * + * @return the path + * + * @throws IOException + * if an I/O error occurs writing to or creating the file, or the + * text cannot be encoded using the specified charset + * @throws UnsupportedOperationException + * if an unsupported option is specified + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. + */ + public static Path write(Path path, Iterable lines, + Charset cs, OpenOption... options) + throws IOException + { + // ensure lines is not null before opening file + Objects.nonNull(lines); + CharsetEncoder encoder = cs.newEncoder(); + OutputStream out = newOutputStream(path, options); + try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, encoder))) { + for (CharSequence line: lines) { + writer.append(line); + writer.newLine(); + } } + return path; } } diff --git a/src/share/classes/java/nio/file/LinkOption.java b/src/share/classes/java/nio/file/LinkOption.java index 7c8d97d4c3f272504180411954dd6b9817ccdec1..13a42ef7143a2f7e3ebeff46c5445c88e7b37674 100644 --- a/src/share/classes/java/nio/file/LinkOption.java +++ b/src/share/classes/java/nio/file/LinkOption.java @@ -35,8 +35,8 @@ public enum LinkOption implements OpenOption, CopyOption { /** * Do not follow symbolic links. * - * @see FileRef#getFileAttributeView(Class,LinkOption[]) - * @see Path#copyTo + * @see Files#getFileAttributeView(Path,Class,LinkOption[]) + * @see Files#copy * @see SecureDirectoryStream#newByteChannel */ NOFOLLOW_LINKS; diff --git a/src/share/classes/java/nio/file/LinkPermission.java b/src/share/classes/java/nio/file/LinkPermission.java index 25d799f8c744d7316bc536f4f8eb293ab3ecb43d..161d1b9d7af312e3d957b4c23ecd149d0ad8c6aa 100644 --- a/src/share/classes/java/nio/file/LinkPermission.java +++ b/src/share/classes/java/nio/file/LinkPermission.java @@ -59,8 +59,8 @@ import java.security.BasicPermission; * * @since 1.7 * - * @see Path#createLink - * @see Path#createSymbolicLink + * @see Files#createLink + * @see Files#createSymbolicLink */ public final class LinkPermission extends BasicPermission { static final long serialVersionUID = -1441492453772213220L; diff --git a/src/share/classes/java/nio/file/OpenOption.java b/src/share/classes/java/nio/file/OpenOption.java index aae5e27911dcd21f13ab7eaca9b619655d411545..522d5ddc4f02cb67867d1f4a19d0e82eb6d4dd3d 100644 --- a/src/share/classes/java/nio/file/OpenOption.java +++ b/src/share/classes/java/nio/file/OpenOption.java @@ -29,8 +29,8 @@ package java.nio.file; * An object that configures how to open or create a file. * *

Objects of this type are used by methods such as {@link - * Path#newOutputStream(OpenOption[]) newOutputStream}, {@link - * Path#newByteChannel newByteChannel}, {@link + * Files#newOutputStream(Path,OpenOption[]) newOutputStream}, {@link + * Files#newByteChannel newByteChannel}, {@link * java.nio.channels.FileChannel#open FileChannel.open}, and {@link * java.nio.channels.AsynchronousFileChannel#open AsynchronousFileChannel.open} * when opening or creating a file. diff --git a/src/share/classes/java/nio/file/Path.java b/src/share/classes/java/nio/file/Path.java index b41e03f91beab98a35f1fdb02b191c7caa0db5f8..85436b01d9ae47eb3cc0c29d20de56c378b11f61 100644 --- a/src/share/classes/java/nio/file/Path.java +++ b/src/share/classes/java/nio/file/Path.java @@ -25,147 +25,95 @@ package java.nio.file; -import java.nio.file.attribute.*; -import java.nio.channels.SeekableByteChannel; +import java.io.File; import java.io.IOException; -import java.io.OutputStream; import java.net.URI; import java.util.Iterator; -import java.util.Set; /** - * A file reference that locates a file using a system dependent path. The file - * is not required to exist. + * An object that may be used to locate a file in a file system. It will + * typically represent a system dependent file path. * - *

On many platforms a path is the means to locate and access files - * in a file system. A path is hierarchical and composed of a sequence of - * directory and file name elements separated by a special separator or - * delimiter. - * - *

Path operations

- * - *

A system dependent path represented by this class is conceptually a - * sequence of name elements and optionally a root component. The name - * that is farthest from the root of the directory hierarchy is the - * name of a file or directory. The other elements are directory names. The root - * component typically identifies a file system hierarchy. A {@code Path} can - * represent a root, a root and a sequence of names, or simply one or more name - * elements. It defines the {@link #getName() getName}, {@link #getParent - * getParent}, {@link #getRoot getRoot}, and {@link #subpath subpath} methods - * to access the components or a subsequence of its name elements. + *

A {@code Path} represents a path that is hierarchical and composed of a + * sequence of directory and file name elements separated by a special separator + * or delimiter. A root component, that identifies a file system + * hierarchy, may also be present. The name element that is farthest + * from the root of the directory hierarchy is the name of a file or directory. + * The other name elements are directory names. A {@code Path} can represent a + * root, a root and a sequence of names, or simply one or more name elements. + * A {@code Path} is considered to be an empty path if it consists + * solely of one name element that is empty. Accessing a file using an + * empty path is equivalent to accessing the default directory of the + * file system. {@code Path} defines the {@link #getFileName() getFileName}, + * {@link #getParent getParent}, {@link #getRoot getRoot}, and {@link #subpath + * subpath} methods to access the path components or a subsequence of its name + * elements. * *

In addition to accessing the components of a path, a {@code Path} also - * defines {@link #resolve(Path) resolve} and {@link #relativize relativize} - * operations. Paths can also be {@link #compareTo compared}, and tested - * against each other using using the {@link #startsWith startsWith} and {@link - * #endsWith endWith} methods. - * - *

File operations

- * - *

A {@code Path} is either absolute or relative. An - * absolute path is complete in that does not need to be combined with another - * path in order to locate a file. All operations on relative paths are first - * resolved against a file system's default directory as if by invoking the - * {@link #toAbsolutePath toAbsolutePath} method. - * - *

In addition to the operations defined by the {@link FileRef} interface, - * this class defines the following operations: + * defines the {@link #resolve(Path) resolve} and {@link #resolveSibling(Path) + * resolveSibling} methods to combine paths. The {@link #relativize relativize} + * method that can be used to construct a relative path between two paths. + * Paths can be {@link #compareTo compared}, and tested against each other using + * the {@link #startsWith startsWith} and {@link #endsWith endWith} methods. * - *

    - *
  • The {@link #newByteChannel newByteChannel} method - * may be used to open a file and obtain a byte channel for reading or - * writing.

  • - *
  • Files may be {@link #createFile(FileAttribute[]) created}, or - * directories may be {@link #createDirectory(FileAttribute[]) created}. - *

  • - *
  • The {@link #delete delete} method may be used to delete a file. - *

  • - *
  • The {@link #checkAccess checkAccess} method may be used to check - * the existence or accessibility of a file.

  • - *
  • The {@link #isSameFile isSameFile} method may be used to test if - * two file references locate the same file.

  • - *
  • The {@link #getFileStore getFileStore} method may be used to - * obtain the {@link FileStore} representing the storage where a file is - * located.

  • - *
  • Directories can be {@link #newDirectoryStream opened} so as to - * iterate over the entries in the directory.

  • - *
  • Files can be {@link #copyTo(Path,CopyOption[]) copied} or - * {@link #moveTo(Path,CopyOption[]) moved}.

  • - *
  • Symbolic links may be {@link #createSymbolicLink created}, or the - * target of a symbolic link may be {@link #readSymbolicLink read}.

  • - *
  • The {@link #toRealPath real} path of an existing file may be - * obtained.

  • - *
+ *

This interface extends {@link Watchable} interface so that a directory + * located by a path can be {@link #register registered} with a {@link + * WatchService} and entries in the directory watched.

* - *

This class implements {@link Watchable} interface so that a directory - * located by a path can be {@link #register registered} with a {@link WatchService}. - * and entries in the directory watched. + *

WARNING: This interface is only intended to be implemented by + * those developing custom file system implementations. Methods may be added to + * this interface in future releases.

* - *

File attributes

- * - * In addition to the {@link #setAttribute setAttribute} and {@link #getAttribute - * getAttribute} methods, the {@code - * java.nio.file.attribute} package provides type-safe and efficient access - * to file attributes or meta-data associated with files. The {@link - * Attributes Attributes} class defines methods that operate on or return file - * attributes. For example, the file type, size, timestamps, and other - * basic meta-data are obtained, in bulk, by invoking the {@link - * Attributes#readBasicFileAttributes Attributes.readBasicFileAttributes} method: + *

Accessing Files

+ *

Paths may be used with the {@link Files} class to operate on files, + * directories, and other types of files. For example, suppose we want a {@link + * java.io.BufferedReader} to read text from a file "{@code access.log}". The + * file is located in a directory "{@code logs}" relative to the current working + * directory and is UTF-8 encoded. *

- *     Path file = ...
- *     BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file);
+ *     Path path = FileSystems.getDefault().getPath("logs", "access.log");
+ *     BufferReader reader = Files.newBufferedReader(path, Charset.forName("UTF-8"));
  * 
* *

Interoperability

- * - *

Paths created by file systems associated with the default {@link + *

Paths associated with the default {@link * java.nio.file.spi.FileSystemProvider provider} are generally interoperable * with the {@link java.io.File java.io.File} class. Paths created by other * providers are unlikely to be interoperable with the abstract path names - * represented by {@code java.io.File}. The {@link java.io.File#toPath - * File.toPath} method may be used to obtain a {@code Path} from the abstract - * path name represented by a {@code java.io.File java.io.File} object. The - * resulting {@code Path} can be used to operate on the same file as the {@code - * java.io.File} object. - * - *

Path objects created by file systems associated with the default - * provider are interoperable with objects created by other file systems created - * by the same provider. Path objects created by file systems associated with - * other providers may not be interoperable with other file systems created by - * the same provider. The reasons for this are provider specific. + * represented by {@code java.io.File}. The {@link java.io.File#toPath toPath} + * method may be used to obtain a {@code Path} from the abstract path name + * represented by a {@code java.io.File} object. The resulting {@code Path} can + * be used to operate on the same file as the {@code java.io.File} object. In + * addition, the {@link #toFile toFile} method is useful to construct a {@code + * File} from the {@code String} representation of a {@code Path}. * *

Concurrency

- * - *

Instances of this class are immutable and safe for use by multiple concurrent - * threads. + *

Implementations of this interface are immutable and safe for use by + * multiple concurrent threads. * * @since 1.7 + * @see Paths */ -public abstract class Path - implements FileRef, Comparable, Iterable, Watchable +public interface Path + extends Comparable, Iterable, Watchable { - /** - * Initializes a new instance of this class. - */ - protected Path() { } - /** * Returns the file system that created this object. * * @return the file system that created this object */ - public abstract FileSystem getFileSystem(); + FileSystem getFileSystem(); /** * Tells whether or not this path is absolute. * - *

An absolute path is complete in that it doesn't need to be - * combined with other path information in order to locate a file. + *

An absolute path is complete in that it doesn't need to be combined + * with other path information in order to locate a file. * * @return {@code true} if, and only if, this path is absolute */ - public abstract boolean isAbsolute(); + boolean isAbsolute(); /** * Returns the root component of this path as a {@code Path} object, @@ -174,17 +122,17 @@ public abstract class Path * @return a path representing the root component of this path, * or {@code null} */ - public abstract Path getRoot(); + Path getRoot(); /** - * Returns the name of the file or directory denoted by this path. The - * file name is the farthest element from the root in the directory - * hierarchy. + * Returns the name of the file or directory denoted by this path as a + * {@code Path} object. The file name is the farthest element from + * the root in the directory hierarchy. * * @return a path representing the name of the file or directory, or * {@code null} if this path has zero elements */ - public abstract Path getName(); + Path getFileName(); /** * Returns the parent path, or {@code null} if this path does not @@ -209,7 +157,7 @@ public abstract class Path * * @return a path representing the path's parent */ - public abstract Path getParent(); + Path getParent(); /** * Returns the number of name elements in the path. @@ -217,10 +165,10 @@ public abstract class Path * @return the number of elements in the path, or {@code 0} if this path * only represents a root component */ - public abstract int getNameCount(); + int getNameCount(); - /** - * Returns a name element of this path. + /** + * Returns a name element of this path as a {@code Path} object. * *

The {@code index} parameter is the index of the name element to return. * The element that is closest to the root in the directory hierarchy @@ -237,7 +185,7 @@ public abstract class Path * equal to the number of elements, or this path has zero name * elements */ - public abstract Path getName(int index); + Path getName(int index); /** * Returns a relative {@code Path} that is a subsequence of the name @@ -264,7 +212,7 @@ public abstract class Path * the number of elements. If {@code endIndex} is less than or * equal to {@code beginIndex}, or larger than the number of elements. */ - public abstract Path subpath(int beginIndex, int endIndex); + Path subpath(int beginIndex, int endIndex); /** * Tests if this path starts with the given path. @@ -286,7 +234,25 @@ public abstract class Path * @return {@code true} if this path starts with the given path; otherwise * {@code false} */ - public abstract boolean startsWith(Path other); + boolean startsWith(Path other); + + /** + * Tests if this path starts with a {@code Path}, constructed by converting + * the given path string, in exactly the manner specified by the {@link + * #startsWith(Path) startsWith(Path)} method. On UNIX for example, the path + * "{@code foo/bar}" starts with "{@code foo}" and "{@code foo/bar}". It + * does not start with "{@code f}" or "{@code fo}". + * + * @param other + * the given path string + * + * @return {@code true} if this path starts with the given path; otherwise + * {@code false} + * + * @throws InvalidPathException + * If the path string cannot be converted to a Path. + */ + boolean startsWith(String other); /** * Tests if this path ends with the given path. @@ -310,7 +276,25 @@ public abstract class Path * @return {@code true} if this path ends with the given path; otherwise * {@code false} */ - public abstract boolean endsWith(Path other); + boolean endsWith(Path other); + + /** + * Tests if this path ends with a {@code Path}, constructed by converting + * the given path string, in exactly the manner specified by the {@link + * #endsWith(Path) endsWith(Path)} method. On UNIX for example, the path + * "{@code foo/bar}" ends with "{@code foo/bar}" and "{@code bar}". It does + * not end with "{@code r}" or "{@code /bar}". + * + * @param other + * the given path string + * + * @return {@code true} if this path starts with the given path; otherwise + * {@code false} + * + * @throws InvalidPathException + * If the path string cannot be converted to a Path. + */ + boolean endsWith(String other); /** * Returns a path that is this path with redundant name elements eliminated. @@ -330,14 +314,14 @@ public abstract class Path * path may result in the path that locates a different file than the original * path. This can arise when the preceding name is a symbolic link. * - * @return the resulting path, or this path if it does not contain - * redundant name elements, or {@code null} if this path does not - * have a root component and all name elements are redundant + * @return the resulting path or this path if it does not contain + * redundant name elements; an empty path is returned if this path + * does have a root component and all name elements are redundant * * @see #getParent * @see #toRealPath */ - public abstract Path normalize(); + Path normalize(); // -- resolution and relativization -- @@ -346,28 +330,31 @@ public abstract class Path * *

If the {@code other} parameter is an {@link #isAbsolute() absolute} * path then this method trivially returns {@code other}. If {@code other} - * is {@code null} then this path is returned. Otherwise this method - * considers this path to be a directory and resolves the given path - * against this path. In the simplest case, the given path does not have - * a {@link #getRoot root} component, in which case this method joins - * the given path to this path and returns a resulting path that {@link - * #endsWith ends} with the given path. Where the given path has a root - * component then resolution is highly implementation dependent and therefore - * unspecified. + * is an empty path then this method trivially returns this path. + * Otherwise this method considers this path to be a directory and resolves + * the given path against this path. In the simplest case, the given path + * does not have a {@link #getRoot root} component, in which case this method + * joins the given path to this path and returns a resulting path + * that {@link #endsWith ends} with the given path. Where the given path has + * a root component then resolution is highly implementation dependent and + * therefore unspecified. * * @param other - * the path to resolve against this path; can be {@code null} + * the path to resolve against this path * * @return the resulting path * * @see #relativize */ - public abstract Path resolve(Path other); + Path resolve(Path other); /** * Converts a given path string to a {@code Path} and resolves it against * this {@code Path} in exactly the manner specified by the {@link - * #resolve(Path) resolve} method. + * #resolve(Path) resolve} method. For example, suppose that the name + * separator is "{@code /}" and a path represents "{@code foo/bar}", then + * invoking this method with the path string "{@code gus}" will result in + * the {@code Path} "{@code foo/bar/gus}". * * @param other * the path string to resolve against this path @@ -375,11 +362,49 @@ public abstract class Path * @return the resulting path * * @throws InvalidPathException - * If the path string cannot be converted to a Path. + * if the path string cannot be converted to a Path. + * + * @see FileSystem#getPath + */ + Path resolve(String other); + + /** + * Resolves the given path against this path's {@link #getParent parent} + * path. This is useful where a file name needs to be replaced with + * another file name. For example, suppose that the name separator is + * "{@code /}" and a path represents "{@code dir1/dir2/foo}", then invoking + * this method with the {@code Path} "{@code bar}" will result in the {@code + * Path} "{@code dir1/dir2/bar}". If this path does not have a parent path, + * or {@code other} is {@link #isAbsolute() absolute}, then this method + * returns {@code other}. If {@code other} is an empty path then this method + * returns this path's parent, or where this path doesn't have a parent, the + * empty path. + * + * @param other + * the path to resolve against this path's parent + * + * @return the resulting path + * + * @see #resolve(Path) + */ + Path resolveSibling(Path other); + + /** + * Converts a given path string to a {@code Path} and resolves it against + * this path's {@link #getParent parent} path in exactly the manner + * specified by the {@link #resolveSibling(Path) resolveSibling} method. + * + * @param other + * the path string to resolve against this path's parent + * + * @return the resulting path + * + * @throws InvalidPathException + * if the path string cannot be converted to a Path. * * @see FileSystem#getPath */ - public abstract Path resolve(String other); + Path resolveSibling(String other); /** * Constructs a relative path between this path and a given path. @@ -395,17 +420,17 @@ public abstract class Path * constructed if only one of the paths have a root component. Where both * paths have a root component then it is implementation dependent if a * relative path can be constructed. If this path and the given path are - * {@link #equals equal} then {@code null} is returned. + * {@link #equals equal} then an empty path is returned. * - *

For any two paths p and q, where q does not have - * a root component, + *

For any two {@link #normalize normalized} paths p and + * q, where q does not have a root component, *

* p.relativize(p.resolve(q)).equals(q) *
* *

When symbolic links are supported, then whether the resulting path, * when resolved against this path, yields a path that can be used to locate - * the {@link #isSameFile same} file as {@code other} is implementation + * the {@link Files#isSameFile same} file as {@code other} is implementation * dependent. For example, if this path is {@code "/a/b"} and the given * path is {@code "/a/x"} then the resulting relative path may be {@code * "../x"}. If {@code "b"} is a symbolic link then is implementation @@ -414,185 +439,14 @@ public abstract class Path * @param other * the path to relativize against this path * - * @return the resulting relative path, or {@code null} if both paths are + * @return the resulting relative path, or an empty path if both paths are * equal * * @throws IllegalArgumentException * if {@code other} is not a {@code Path} that can be relativized * against this path */ - public abstract Path relativize(Path other); - - // -- file operations -- - - /** - * Deletes the file located by this path. - * - *

An implementation may require to examine the file to determine if the - * file is a directory. Consequently this method may not be atomic with respect - * to other file system operations. If the file is a symbolic link then the - * symbolic link itself, not the final target of the link, is deleted. - * - *

If the file is a directory then the directory must be empty. In some - * implementations a directory has entries for special files or links that - * are created when the directory is created. In such implementations a - * directory is considered empty when only the special entries exist. - * - *

On some operating systems it may not be possible to remove a file when - * it is open and in use by this Java virtual machine or other programs. - * - * @throws NoSuchFileException - * if the file does not exist (optional specific exception) - * @throws DirectoryNotEmptyException - * if the file is a directory and could not otherwise be deleted - * because the directory is not empty (optional specific - * exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkDelete(String)} method - * is invoked to check delete access to the file - */ - public abstract void delete() throws IOException; - - /** - * Deletes the file located by this path, if it exists. - * - *

As with the {@link #delete delete()} method, an implementation may - * need to examine the file to determine if the file is a directory. - * Consequently this method may not be atomic with respect to other file - * system operations. If the file is a symbolic link, then the symbolic - * link itself, not the final target of the link, is deleted. - * - *

If the file is a directory then the directory must be empty. In some - * implementations a directory has entries for special files or links that - * are created when the directory is created. In such implementations a - * directory is considered empty when only the special entries exist. - * - *

On some operating systems it may not be possible to remove a file when - * it is open and in use by this Java virtual machine or other programs. - * - * @throws DirectoryNotEmptyException - * if the file is a directory and could not otherwise be deleted - * because the directory is not empty (optional specific - * exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkDelete(String)} method - * is invoked to check delete access to the file. - */ - public abstract void deleteIfExists() throws IOException; - - /** - * Creates a symbolic link to a target (optional operation). - * - *

The {@code target} parameter is the target of the link. It may be an - * {@link Path#isAbsolute absolute} or relative path and may not exist. When - * the target is a relative path then file system operations on the resulting - * link are relative to the path of the link. - * - *

The {@code attrs} parameter is an optional array of {@link FileAttribute - * attributes} to set atomically when creating the link. Each attribute is - * identified by its {@link FileAttribute#name name}. If more than one attribute - * of the same name is included in the array then all but the last occurrence - * is ignored. - * - *

Where symbolic links are supported, but the underlying {@link FileStore} - * does not support symbolic links, then this may fail with an {@link - * IOException}. Additionally, some operating systems may require that the - * Java virtual machine be started with implementation specific privileges to - * create symbolic links, in which case this method may throw {@code IOException}. - * - * @param target - * the target of the symbolic link - * @param attrs - * the array of attributes to set atomically when creating the - * symbolic link - * - * @return this path - * - * @throws UnsupportedOperationException - * if the implementation does not support symbolic links or the - * array contains an attribute that cannot be set atomically when - * creating the symbolic link - * @throws FileAlreadyExistsException - * if a file with the name already exists (optional specific - * exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager - * is installed, it denies {@link LinkPermission}("symbolic") - * or its {@link SecurityManager#checkWrite(String) checkWrite} - * method denies write access to the path of the symbolic link. - */ - public abstract Path createSymbolicLink(Path target, FileAttribute... attrs) - throws IOException; - - /** - * Creates a new link (directory entry) for an existing file (optional - * operation). - * - *

This path locates the directory entry to create. The {@code existing} - * parameter is the path to an existing file. This method creates a new - * directory entry for the file so that it can be accessed using this path. - * On some file systems this is known as creating a "hard link". Whether the - * file attributes are maintained for the file or for each directory entry - * is file system specific and therefore not specified. Typically, a file - * system requires that all links (directory entries) for a file be on the - * same file system. Furthermore, on some platforms, the Java virtual machine - * may require to be started with implementation specific privileges to - * create hard links or to create links to directories. - * - * @param existing - * a reference to an existing file - * - * @return this path - * - * @throws UnsupportedOperationException - * if the implementation does not support adding an existing file - * to a directory - * @throws FileAlreadyExistsException - * if the entry could not otherwise be created because a file of - * that name already exists (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager - * is installed, it denies {@link LinkPermission}("hard") - * or its {@link SecurityManager#checkWrite(String) checkWrite} - * method denies write access to both this path and the path of the - * existing file. - */ - public abstract Path createLink(Path existing) throws IOException; - - /** - * Reads the target of a symbolic link (optional operation). - * - *

If the file system supports symbolic - * links then this method is used to read the target of the link, failing - * if the file is not a symbolic link. The target of the link need not exist. - * The returned {@code Path} object will be associated with the same file - * system as this {@code Path}. - * - * @return a {@code Path} object representing the target of the link - * - * @throws UnsupportedOperationException - * if the implementation does not support symbolic links - * @throws NotLinkException - * if the target could otherwise not be read because the file - * is not a symbolic link (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager - * is installed, it checks that {@code FilePermission} has been - * granted with the "{@code readlink}" action to read the link. - */ - public abstract Path readSymbolicLink() throws IOException; + Path relativize(Path other); /** * Returns a URI to represent this path. @@ -647,7 +501,7 @@ public abstract class Path * is installed, the {@link #toAbsolutePath toAbsolutePath} method * throws a security exception. */ - public abstract URI toUri(); + URI toUri(); /** * Returns a {@code Path} object representing the absolute path of this @@ -670,14 +524,14 @@ public abstract class Path * checkPropertyAccess} method is invoked to check access to the * system property {@code user.dir} */ - public abstract Path toAbsolutePath(); + Path toAbsolutePath(); /** * Returns the real path of an existing file. * *

The precise definition of this method is implementation dependent but * in general it derives from this path, an {@link #isAbsolute absolute} - * path that locates the {@link #isSameFile same} file as this path, but + * path that locates the {@link Files#isSameFile same} file as this path, but * with name elements that represent the actual name of the directories * and the file. For example, where filename comparisons on a file system * are case insensitive then the name elements represent the names in their @@ -713,756 +567,25 @@ public abstract class Path * checkPropertyAccess} method is invoked to check access to the * system property {@code user.dir} */ - public abstract Path toRealPath(boolean resolveLinks) throws IOException; - - /** - * Copy the file located by this path to a target location. - * - *

This method copies the file located by this {@code Path} to the - * target location with the {@code options} parameter specifying how the - * copy is performed. By default, the copy fails if the target file already - * exists, except if the source and target are the {@link #isSameFile same} - * file, in which case this method has no effect. File attributes are not - * required to be copied to the target file. If symbolic links are supported, - * and the file is a symbolic link, then the final target of the link is copied. - * If the file is a directory then it creates an empty directory in the target - * location (entries in the directory are not copied). This method can be - * used with the {@link Files#walkFileTree Files.walkFileTree} utility - * method to copy a directory and all entries in the directory, or an entire - * file-tree where required. - * - *

The {@code options} parameter is an array of options and may contain - * any of the following: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Option Description
{@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} If the target file exists, then the target file is replaced if it - * is not a non-empty directory. If the target file exists and is a - * symbolic link, then the symbolic link itself, not the target of - * the link, is replaced.
{@link StandardCopyOption#COPY_ATTRIBUTES COPY_ATTRIBUTES} Attempts to copy the file attributes associated with this file to - * the target file. The exact file attributes that are copied is platform - * and file system dependent and therefore unspecified. Minimally, the - * {@link BasicFileAttributes#lastModifiedTime last-modified-time} is - * copied to the target file if supported by both the source and target - * file store. Copying of file timestamps may result in precision - * loss.
{@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} Symbolic links are not followed. If the file, located by this path, - * is a symbolic link, then the symbolic link itself, not the target of - * the link, is copied. It is implementation specific if file attributes - * can be copied to the new link. In other words, the {@code - * COPY_ATTRIBUTES} option may be ignored when copying a symbolic link.
- * - *

An implementation of this interface may support additional - * implementation specific options. - * - *

Copying a file is not an atomic operation. If an {@link IOException} - * is thrown then it possible that the target file is incomplete or some of - * its file attributes have not been copied from the source file. When the - * {@code REPLACE_EXISTING} option is specified and the target file exists, - * then the target file is replaced. The check for the existence of the file - * and the creation of the new file may not be atomic with respect to other - * file system activities. - * - * @param target - * the target location - * @param options - * options specifying how the copy should be done - * - * @return the target - * - * @throws UnsupportedOperationException - * if the array contains a copy option that is not supported - * @throws FileAlreadyExistsException - * if the target file exists and cannot be replaced because the - * {@code REPLACE_EXISTING} option is not specified, or the target - * file is a non-empty directory (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the source file, the - * {@link SecurityManager#checkWrite(String) checkWrite} is invoked - * to check write access to the target file. If a symbolic link is - * copied the security manager is invoked to check {@link - * LinkPermission}{@code ("symbolic")}. - */ - public abstract Path copyTo(Path target, CopyOption... options) - throws IOException; - - /** - * Move or rename the file located by this path to a target location. - * - *

By default, this method attempts to move the file to the target - * location, failing if the target file exists except if the source and - * target are the {@link #isSameFile same} file, in which case this method - * has no effect. If the file is a symbolic link then the symbolic link - * itself, not the target of the link, is moved. This method may be - * invoked to move an empty directory. In some implementations a directory - * has entries for special files or links that are created when the - * directory is created. In such implementations a directory is considered - * empty when only the special entries exist. When invoked to move a - * directory that is not empty then the directory is moved if it does not - * require moving the entries in the directory. For example, renaming a - * directory on the same {@link FileStore} will usually not require moving - * the entries in the directory. When moving a directory requires that its - * entries be moved then this method fails (by throwing an {@code - * IOException}). To move a file tree may involve copying rather - * than moving directories and this can be done using the {@link - * #copyTo copyTo} method in conjunction with the {@link - * Files#walkFileTree Files.walkFileTree} utility method. - * - *

The {@code options} parameter is an array of options and may contain - * any of the following: - * - * - * - * - * - * - * - * - * - * - *
Option Description
{@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} If the target file exists, then the target file is replaced if it - * is not a non-empty directory. If the target file exists and is a - * symbolic link, then the symbolic link itself, not the target of - * the link, is replaced.
{@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} The move is performed as an atomic file system operation and all - * other options are ignored. If the target file exists then it is - * implementation specific if the existing file is replaced or this method - * fails by throwing an {@link IOException}. If the move cannot be - * performed as an atomic file system operation then {@link - * AtomicMoveNotSupportedException} is thrown. This can arise, for - * example, when the target location is on a different {@code FileStore} - * and would require that the file be copied, or target location is - * associated with a different provider to this object.
- * - *

An implementation of this interface may support additional - * implementation specific options. - * - *

Where the move requires that the file be copied then the {@link - * BasicFileAttributes#lastModifiedTime last-modified-time} is copied to the - * new file. An implementation may also attempt to copy other file - * attributes but is not required to fail if the file attributes cannot be - * copied. When the move is performed as a non-atomic operation, and a {@code - * IOException} is thrown, then the state of the files is not defined. The - * original file and the target file may both exist, the target file may be - * incomplete or some of its file attributes may not been copied from the - * original file. - * - * @param target - * the target location - * @param options - * options specifying how the move should be done - * - * @return the target - * - * @throws UnsupportedOperationException - * if the array contains a copy option that is not supported - * @throws FileAlreadyExistsException - * if the target file exists and cannot be replaced because the - * {@code REPLACE_EXISTING} option is not specified, or the target - * file is a non-empty directory - * @throws AtomicMoveNotSupportedException - * if the options array contains the {@code ATOMIC_MOVE} option but - * the file cannot be moved as an atomic file system operation. - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkWrite(String) checkWrite} - * method is invoked to check write access to both the source and - * target file. - */ - public abstract Path moveTo(Path target, CopyOption... options) - throws IOException; - - /** - * Opens the directory referenced by this object, returning a {@code - * DirectoryStream} to iterate over all entries in the directory. The - * elements returned by the directory stream's {@link DirectoryStream#iterator - * iterator} are of type {@code Path}, each one representing an entry in the - * directory. The {@code Path} objects are obtained as if by {@link - * #resolve(Path) resolving} the name of the directory entry against this - * path. - * - *

The directory stream's {@code close} method should be invoked after - * iteration is completed so as to free any resources held for the open - * directory. - * - *

When an implementation supports operations on entries in the - * directory that execute in a race-free manner then the returned directory - * stream is a {@link SecureDirectoryStream}. - * - * @return a new and open {@code DirectoryStream} object - * - * @throws NotDirectoryException - * if the file could not otherwise be opened because it is not - * a directory (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the directory. - */ - public abstract DirectoryStream newDirectoryStream() - throws IOException; - - /** - * Opens the directory referenced by this object, returning a {@code - * DirectoryStream} to iterate over the entries in the directory. The - * elements returned by the directory stream's {@link DirectoryStream#iterator - * iterator} are of type {@code Path}, each one representing an entry in the - * directory. The {@code Path} objects are obtained as if by {@link - * #resolve(Path) resolving} the name of the directory entry against this - * path. The entries returned by the iterator are filtered by matching the - * {@code String} representation of their file names against the given - * globbing pattern. - * - *

For example, suppose we want to iterate over the files ending with - * ".java" in a directory: - *

-     *     Path dir = ...
-     *     DirectoryStream<Path> stream = dir.newDirectoryStream("*.java");
-     * 
- * - *

The globbing pattern is specified by the {@link - * FileSystem#getPathMatcher getPathMatcher} method. - * - *

The directory stream's {@code close} method should be invoked after - * iteration is completed so as to free any resources held for the open - * directory. - * - *

When an implementation supports operations on entries in the - * directory that execute in a race-free manner then the returned directory - * stream is a {@link SecureDirectoryStream}. - * - * @param glob - * the glob pattern - * - * @return a new and open {@code DirectoryStream} object - * - * @throws java.util.regex.PatternSyntaxException - * if the pattern is invalid - * @throws NotDirectoryException - * if the file could not otherwise be opened because it is not - * a directory (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the directory. - */ - public abstract DirectoryStream newDirectoryStream(String glob) - throws IOException; - - /** - * Opens the directory referenced by this object, returning a {@code - * DirectoryStream} to iterate over the entries in the directory. The - * elements returned by the directory stream's {@link DirectoryStream#iterator - * iterator} are of type {@code Path}, each one representing an entry in the - * directory. The {@code Path} objects are obtained as if by {@link - * #resolve(Path) resolving} the name of the directory entry against this - * path. The entries returned by the iterator are filtered by the given - * {@link DirectoryStream.Filter filter}. - * - *

The directory stream's {@code close} method should be invoked after - * iteration is completed so as to free any resources held for the open - * directory. - * - *

Where the filter terminates due to an uncaught error or runtime - * exception then it is propagated to the {@link Iterator#hasNext() - * hasNext} or {@link Iterator#next() next} method. Where an {@code - * IOException} is thrown, it results in the {@code hasNext} or {@code - * next} method throwing a {@link DirectoryIteratorException} with the - * {@code IOException} as the cause. - * - *

When an implementation supports operations on entries in the - * directory that execute in a race-free manner then the returned directory - * stream is a {@link SecureDirectoryStream}. - * - *

Usage Example: - * Suppose we want to iterate over the files in a directory that are - * larger than 8K. - *

-     *     DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
-     *         public boolean accept(Path file) throws IOException {
-     *             long size = Attributes.readBasicFileAttributes(file).size();
-     *             return (size > 8192L);
-     *         }
-     *     };
-     *     Path dir = ...
-     *     DirectoryStream<Path> stream = dir.newDirectoryStream(filter);
-     * 
- * @param filter - * the directory stream filter - * - * @return a new and open {@code DirectoryStream} object - * - * @throws NotDirectoryException - * if the file could not otherwise be opened because it is not - * a directory (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the directory. - */ - public abstract DirectoryStream newDirectoryStream(DirectoryStream.Filter filter) - throws IOException; - - /** - * Creates a new and empty file, failing if the file already exists. - * - *

This {@code Path} locates the file to create. The check for the - * existence of the file and the creation of the new file if it does not - * exist are a single operation that is atomic with respect to all other - * filesystem activities that might affect the directory. - * - *

The {@code attrs} parameter is an optional array of {@link FileAttribute - * file-attributes} to set atomically when creating the file. Each attribute - * is identified by its {@link FileAttribute#name name}. If more than one - * attribute of the same name is included in the array then all but the last - * occurrence is ignored. - * - * @param attrs - * an optional list of file attributes to set atomically when - * creating the file - * - * @return this path - * - * @throws UnsupportedOperationException - * if the array contains an attribute that cannot be set atomically - * when creating the file - * @throws FileAlreadyExistsException - * if a file of that name already exists - * (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkWrite(String) checkWrite} - * method is invoked to check write access to the new file. - */ - public abstract Path createFile(FileAttribute... attrs) throws IOException; + Path toRealPath(boolean resolveLinks) throws IOException; /** - * Creates a new directory. + * Returns a {@link File} object representing this path. Where this {@code + * Path} is associated with the default provider, then this method is + * equivalent to returning a {@code File} object constructed with the + * {@code String} representation of this path. * - *

This {@code Path} locates the directory to create. The check for the - * existence of the file and the creation of the directory if it does not - * exist are a single operation that is atomic with respect to all other - * filesystem activities that might affect the directory. + *

If this path was created by invoking the {@code File} {@link + * File#toPath toPath} method then there is no guarantee that the {@code + * File} object returned by this method is {@link #equals equal} to the + * original {@code File}. * - *

The {@code attrs} parameter is an optional array of {@link FileAttribute - * file-attributes} to set atomically when creating the directory. Each - * file attribute is identified by its {@link FileAttribute#name name}. If - * more than one attribute of the same name is included in the array then all - * but the last occurrence is ignored. - * - * @param attrs - * an optional list of file attributes to set atomically when - * creating the directory - * - * @return this path + * @return a {@code File} object representing this path * * @throws UnsupportedOperationException - * if the array contains an attribute that cannot be set atomically - * when creating the directory - * @throws FileAlreadyExistsException - * if a directory could not otherwise be created because a file of - * that name already exists (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkWrite(String) checkWrite} - * method is invoked to check write access to the new directory. - * - * @see Files#createDirectories + * if this {@code Path} is not associated with the default provider */ - public abstract Path createDirectory(FileAttribute... attrs) - throws IOException; - - /** - * Opens or creates a file, returning a seekable byte channel to access the - * file. - * - *

The {@code options} parameter determines how the file is opened. - * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE WRITE} - * options determine if the file should be opened for reading and/or writing. - * If neither option (or the {@link StandardOpenOption#APPEND APPEND} - * option) is contained in the array then the file is opened for reading. - * By default reading or writing commences at the beginning of the file. - * - *

In the addition to {@code READ} and {@code WRITE}, the following - * options may be present: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Option Description
{@link StandardOpenOption#APPEND APPEND} If this option is present then the file is opened for writing and - * each invocation of the channel's {@code write} method first advances - * the position to the end of the file and then writes the requested - * data. Whether the advancement of the position and the writing of the - * data are done in a single atomic operation is system-dependent and - * therefore unspecified. This option may not be used in conjunction - * with the {@code READ} or {@code TRUNCATE_EXISTING} options.
{@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} If this option is present then the existing file is truncated to - * a size of 0 bytes. This option is ignored when the file is opened only - * for reading.
{@link StandardOpenOption#CREATE_NEW CREATE_NEW} If this option is present then a new file is created, failing if - * the file already exists or is a symbolic link. When creating a file the - * check for the existence of the file and the creation of the file if it - * does not exist is atomic with respect to other file system operations. - * This option is ignored when the file is opened only for reading.
{@link StandardOpenOption#CREATE CREATE} If this option is present then an existing file is opened if it - * exists, otherwise a new file is created. This option is ignored if the - * {@code CREATE_NEW} option is also present or the file is opened only - * for reading.
{@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} When this option is present then the implementation makes a - * best effort attempt to delete the file when closed by the - * {@link SeekableByteChannel#close close} method. If the {@code close} - * method is not invoked then a best effort attempt is made to - * delete the file when the Java virtual machine terminates.
{@link StandardOpenOption#SPARSE SPARSE} When creating a new file this option is a hint that the - * new file will be sparse. This option is ignored when not creating - * a new file.
{@link StandardOpenOption#SYNC SYNC} Requires that every update to the file's content or metadata be - * written synchronously to the underlying storage device. (see Synchronized I/O file - * integrity).
{@link StandardOpenOption#DSYNC DSYNC} Requires that every update to the file's content be written - * synchronously to the underlying storage device. (see Synchronized I/O file - * integrity).
- * - *

An implementation may also support additional implementation specific - * options. - * - *

The {@code attrs} parameter is an optional array of file {@link - * FileAttribute file-attributes} to set atomically when a new file is created. - * - *

In the case of the default provider, the returned seekable byte channel - * is a {@link java.nio.channels.FileChannel}. - * - *

Usage Examples: - *

-     *     Path file = ...
-     *
-     *     // open file for reading
-     *     ReadableByteChannel rbc = file.newByteChannel(EnumSet.of(READ)));
-     *
-     *     // open file for writing to the end of an existing file, creating
-     *     // the file if it doesn't already exist
-     *     WritableByteChannel wbc = file.newByteChannel(EnumSet.of(CREATE,APPEND));
-     *
-     *     // create file with initial permissions, opening it for both reading and writing
-     *     FileAttribute<Set<PosixFilePermission>> perms = ...
-     *     SeekableByteChannel sbc = file.newByteChannel(EnumSet.of(CREATE_NEW,READ,WRITE), perms);
-     * 
- * - * @param options - * Options specifying how the file is opened - * @param attrs - * An optional list of file attributes to set atomically when - * creating the file - * - * @return a new seekable byte channel - * - * @throws IllegalArgumentException - * if the set contains an invalid combination of options - * @throws UnsupportedOperationException - * if an unsupported open option is specified or the array contains - * attributes that cannot be set atomically when creating the file - * @throws FileAlreadyExistsException - * if a file of that name already exists and the {@link - * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified - * (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the path if the file is - * opened for reading. The {@link SecurityManager#checkWrite(String) - * checkWrite} method is invoked to check write access to the path - * if the file is opened for writing. - */ - public abstract SeekableByteChannel newByteChannel(Set options, - FileAttribute... attrs) - throws IOException; - - /** - * Opens or creates a file, returning a seekable byte channel to access the - * file. - * - *

This method opens or creates a file in exactly the manner specified - * by the {@link Path#newByteChannel(Set,FileAttribute[]) newByteChannel} - * method. - * - * @param options - * options specifying how the file is opened - * - * @return a new seekable byte channel - * - * @throws IllegalArgumentException - * if the set contains an invalid combination of options - * @throws UnsupportedOperationException - * if an unsupported open option is specified - * @throws FileAlreadyExistsException - * if a file of that name already exists and the {@link - * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified - * (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the path if the file is - * opened for reading. The {@link SecurityManager#checkWrite(String) - * checkWrite} method is invoked to check write access to the path - * if the file is opened for writing. - */ - public abstract SeekableByteChannel newByteChannel(OpenOption... options) - throws IOException; - - /** - * Opens or creates the file located by this object for writing, returning - * an output stream to write bytes to the file. - * - *

This method opens or creates a file in exactly the manner specified - * by the {@link Path#newByteChannel(Set,FileAttribute[]) newByteChannel} - * method except that the {@link StandardOpenOption#READ READ} option may not - * be present in the array of open options. - * - * @param options - * options specifying how the file is opened - * - * @return a new output stream - * - * @throws IllegalArgumentException {@inheritDoc} - * @throws UnsupportedOperationException {@inheritDoc} - * @throws IOException {@inheritDoc} - * @throws SecurityException {@inheritDoc} - */ - @Override - public abstract OutputStream newOutputStream(OpenOption... options) - throws IOException; - - /** - * Tells whether or not the file located by this object is considered - * hidden. The exact definition of hidden is platform or provider - * dependent. On UNIX for example a file is considered to be hidden if its - * name begins with a period character ('.'). On Windows a file is - * considered hidden if it isn't a directory and the DOS {@link - * DosFileAttributes#isHidden hidden} attribute is set. - * - *

Depending on the implementation this method may require to access - * the file system to determine if the file is considered hidden. - * - * @return {@code true} if the file is considered hidden - * - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the file. - */ - public abstract boolean isHidden() throws IOException; - - /** - * Checks the existence and optionally the accessibility of the file - * located by this path. - * - *

This method checks the existence of a file and that this Java virtual - * machine has appropriate privileges that would allow it access the file - * according to all of access modes specified in the {@code modes} parameter - * as follows: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Value Description
{@link AccessMode#READ READ} Checks that the file exists and that the Java virtual machine has - * permission to read the file.
{@link AccessMode#WRITE WRITE} Checks that the file exists and that the Java virtual machine has - * permission to write to the file,
{@link AccessMode#EXECUTE EXECUTE} Checks that the file exists and that the Java virtual machine has - * permission to {@link Runtime#exec execute} the file. The semantics - * may differ when checking access to a directory. For example, on UNIX - * systems, checking for {@code EXECUTE} access checks that the Java - * virtual machine has permission to search the directory in order to - * access file or subdirectories.
- * - *

If the {@code modes} parameter is of length zero, then the existence - * of the file is checked. - * - *

This method follows symbolic links if the file referenced by this - * object is a symbolic link. Depending on the implementation, this method - * may require to read file permissions, access control lists, or other - * file attributes in order to check the effective access to the file. To - * determine the effective access to a file may require access to several - * attributes and so in some implementations this method may not be atomic - * with respect to other file system operations. Furthermore, as the result - * of this method is immediately outdated, there is no guarantee that a - * subsequence access will succeed (or even that it will access the same - * file). Care should be taken when using this method in security sensitive - * applications. - * - * @param modes - * The access modes to check; may have zero elements - * - * @throws UnsupportedOperationException - * an implementation is required to support checking for - * {@code READ}, {@code WRITE}, and {@code EXECUTE} access. This - * exception is specified to allow for the {@code Access} enum to - * be extended in future releases. - * @throws NoSuchFileException - * if a file does not exist (optional specific exception) - * @throws AccessDeniedException - * the requested access would be denied or the access cannot be - * determined because the Java virtual machine has insufficient - * privileges or other reasons. (optional specific exception) - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * is invoked when checking read access to the file or only the - * existence of the file, the {@link SecurityManager#checkWrite(String) - * checkWrite} is invoked when checking write access to the file, - * and {@link SecurityManager#checkExec(String) checkExec} is invoked - * when checking execute access. - */ - public abstract void checkAccess(AccessMode... modes) throws IOException; - - /** - * Tests whether the file located by this path exists. - * - *

This convenience method is intended for cases where it is required to - * take action when it can be confirmed that a file exists. This method simply - * invokes the {@link #checkAccess checkAccess} method to check if the file - * exists. If the {@code checkAccess} method succeeds then this method returns - * {@code true}, otherwise if an {@code IOException} is thrown (because the - * file doesn't exist or cannot be accessed by this Java virtual machine) - * then {@code false} is returned. - * - *

Note that the result of this method is immediately outdated. If this - * method indicates the file exists then there is no guarantee that a - * subsequence access will succeed. Care should be taken when using this - * method in security sensitive applications. - * - * @return {@code true} if the file exists; {@code false} if the file does - * not exist or its existence cannot be determined. - * - * @throws SecurityException - * In the case of the default provider, the {@link - * SecurityManager#checkRead(String)} is invoked to check - * read access to the file. - * - * @see #notExists - */ - public abstract boolean exists(); - - /** - * Tests whether the file located by this path does not exist. - * - *

This convenience method is intended for cases where it is required to - * take action when it can be confirmed that a file does not exist. This - * method invokes the {@link #checkAccess checkAccess} method to check if the - * file exists. If the file does not exist then {@code true} is returned, - * otherwise the file exists or cannot be accessed by this Java virtual - * machine and {@code false} is returned. - * - *

Note that this method is not the complement of the {@link #exists - * exists} method. Where it is not possible to determine if a file exists - * or not then both methods return {@code false}. As with the {@code exists} - * method, the result of this method is immediately outdated. If this - * method indicates the file does exist then there is no guarantee that a - * subsequence attempt to create the file will succeed. Care should be taken - * when using this method in security sensitive applications. - * - * @return {@code true} if the file does not exist; {@code false} if the - * file exists or its existence cannot be determined. - * - * @throws SecurityException - * In the case of the default provider, the {@link - * SecurityManager#checkRead(String)} is invoked to check - * read access to the file. - */ - public abstract boolean notExists(); - - /** - * Returns the {@link FileStore} representing the file store where an - * existing file, located by this path, is stored. - * - *

Once a reference to the {@code FileStore} is obtained it is - * implementation specific if operations on the returned {@code FileStore}, - * or {@link FileStoreAttributeView} objects obtained from it, continue - * to depend on the existence of the file. In particular the behavior is not - * defined for the case that the file is deleted or moved to a different - * file store. - * - * @return the file store where the file is stored - * - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to the file, and in - * addition it checks {@link RuntimePermission} - * ("getFileStoreAttributes") - */ - public abstract FileStore getFileStore() throws IOException; + File toFile(); // -- watchable -- @@ -1471,8 +594,8 @@ public abstract class Path * *

In this release, this path locates a directory that exists. The * directory is registered with the watch service so that entries in the - * directory can be watched. The {@code events} parameter is an array of - * events to register and may contain the following events: + * directory can be watched. The {@code events} parameter is the events to + * register and may contain the following events: *

    *
  • {@link StandardWatchEventKind#ENTRY_CREATE ENTRY_CREATE} - * entry created or moved into the directory
  • @@ -1489,10 +612,10 @@ public abstract class Path *

    The set of events may include additional implementation specific * event that are not defined by the enum {@link StandardWatchEventKind} * - *

    The {@code modifiers} parameter is an array of modifiers - * that qualify how the directory is registered. This release does not - * define any standard modifiers. The array may contain - * implementation specific modifiers. + *

    The {@code modifiers} parameter specifies modifiers that + * qualify how the directory is registered. This release does not define any + * standard modifiers. It may contain implementation specific + * modifiers. * *

    Where a file is registered with a watch service by means of a symbolic * link then it is implementation specific if the watch continues to depend @@ -1525,9 +648,9 @@ public abstract class Path * method is invoked to check read access to the file. */ @Override - public abstract WatchKey register(WatchService watcher, - WatchEvent.Kind[] events, - WatchEvent.Modifier... modifiers) + WatchKey register(WatchService watcher, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) throws IOException; /** @@ -1573,8 +696,8 @@ public abstract class Path * method is invoked to check read access to the file. */ @Override - public abstract WatchKey register(WatchService watcher, - WatchEvent.Kind... events) + WatchKey register(WatchService watcher, + WatchEvent.Kind... events) throws IOException; // -- Iterable -- @@ -1591,7 +714,7 @@ public abstract class Path * @return an iterator over the name elements of this path. */ @Override - public abstract Iterator iterator(); + Iterator iterator(); // -- compareTo/equals/hashCode -- @@ -1609,50 +732,7 @@ public abstract class Path * lexicographically greater than the argument */ @Override - public abstract int compareTo(Path other); - - /** - * Tests if the file referenced by this object is the same file referenced - * by another object. - * - *

    If this {@code Path} and the given {@code Path} are {@link - * #equals(Object) equal} then this method returns {@code true} without checking - * if the file exists. If the {@code Path} and the given {@code Path} - * are associated with different providers, or the given {@code Path} is - * {@code null} then this method returns {@code false}. Otherwise, this method - * checks if both {@code Paths} locate the same file, and depending on the - * implementation, may require to open or access both files. - * - *

    If the file system and files remain static, then this method implements - * an equivalence relation for non-null {@code Paths}. - *

      - *
    • It is reflexive: for a non-null {@code Path} {@code f}, - * {@code f.isSameFile(f)} should return {@code true}. - *
    • It is symmetric: for two non-null {@code Path} - * {@code f} and {@code g}, {@code f.isSameFile(g)} will equal - * {@code g.isSameFile(f)}. - *
    • It is transitive: for three {@code Paths} - * {@code f}, {@code g}, and {@code h}, if {@code f.isSameFile(g)} returns - * {@code true} and {@code g.isSameFile(h)} returns {@code true}, then - * {@code f.isSameFile(h)} will return return {@code true}. - *
    - * - * @param other - * the other file reference - * - * @return {@code true} if, and only if, this object and the given object - * locate the same file - * - * @throws IOException - * if an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, the {@link SecurityManager#checkRead(String) checkRead} - * method is invoked to check read access to both files. - * - * @see java.nio.file.attribute.BasicFileAttributes#fileKey - */ - public abstract boolean isSameFile(Path other) throws IOException; + int compareTo(Path other); /** * Tests this path for equality with the given object. @@ -1663,7 +743,9 @@ public abstract class Path *

    Whether or not two path are equal depends on the file system * implementation. In some cases the paths are compared without regard * to case, and others are case sensitive. This method does not access the - * file system and the file is not required to exist. + * file system and the file is not required to exist. Where required, the + * {@link Files#isSameFile isSameFile} method may be used to check if two + * paths locate the same file. * *

    This method satisfies the general contract of the {@link * java.lang.Object#equals(Object) Object.equals} method.

    @@ -1674,8 +756,7 @@ public abstract class Path * @return {@code true} if, and only if, the given object is a {@code Path} * that is identical to this {@code Path} */ - @Override - public abstract boolean equals(Object other); + boolean equals(Object other); /** * Computes a hash code for this path. @@ -1686,8 +767,7 @@ public abstract class Path * * @return the hash-code value for this path */ - @Override - public abstract int hashCode(); + int hashCode(); /** * Returns the string representation of this path. @@ -1701,6 +781,5 @@ public abstract class Path * * @return the string representation of this path */ - @Override - public abstract String toString(); + String toString(); } diff --git a/src/share/classes/java/nio/file/PathMatcher.java b/src/share/classes/java/nio/file/PathMatcher.java index 39af77d6b06522ce2305208db62fa674399dc005..952f18f17f9b820ef9edb4549898dc20e4ddd650 100644 --- a/src/share/classes/java/nio/file/PathMatcher.java +++ b/src/share/classes/java/nio/file/PathMatcher.java @@ -32,7 +32,7 @@ package java.nio.file; * @since 1.7 * * @see FileSystem#getPathMatcher - * @see Path#newDirectoryStream(String) + * @see Files#newDirectoryStream(Path,String) */ public interface PathMatcher { diff --git a/src/share/classes/java/nio/file/Paths.java b/src/share/classes/java/nio/file/Paths.java index be51761c486eb5102e78d58fa5d92ff1009e8fcb..d0906d4443f5f7f89ae01856ce418abaff73ddb4 100644 --- a/src/share/classes/java/nio/file/Paths.java +++ b/src/share/classes/java/nio/file/Paths.java @@ -39,14 +39,27 @@ public final class Paths { private Paths() { } /** - * Constructs a {@code Path} by converting the given path string. + * Converts a path string, or a sequence of strings that when joined form + * a path string, to a {@code Path}. If {@code more} does not specify any + * elements then the value of the {@code first} parameter is the path string + * to convert. If {@code more} specifies one or more elements then each + * non-empty string, including {@code first}, is considered to be a sequence + * of name elements (see {@link Path}) and is joined to form a path string. + * The details as to how the Strings are joined is provider specific but + * typically they will be joined using the {@link FileSystem#getSeparator + * name-separator} as the separator. For example, if the name separator is + * "{@code /}" and {@code getPath("/foo","bar","gus")} is invoked, then the + * path string {@code "/foo/bar/gus"} is converted to a {@code Path}. + * A {@code Path} representing an empty path is returned if {@code first} + * is the empty string and {@code more} does not contain any non-empty + * strings. * *

    The {@code Path} is obtained by invoking the {@link FileSystem#getPath * getPath} method of the {@link FileSystems#getDefault default} {@link * FileSystem}. * - *

    Note that while this method is very convenient, using it will - * imply an assumed reference to the default FileSystem and limit the + *

    Note that while this method is very convenient, using it will imply + * an assumed reference to the default {@code FileSystem} and limit the * utility of the calling code. Hence it should not be used in library code * intended for flexible reuse. A more flexible alternative is to use an * existing {@code Path} instance as an anchor, such as: @@ -55,8 +68,10 @@ public final class Paths { * Path path = dir.resolve("file"); *

* - * @param path - * the path string to convert + * @param first + * the path string or initial part of the path string + * @param more + * additional strings to be joined to form the path string * * @return the resulting {@code Path} * @@ -65,8 +80,8 @@ public final class Paths { * * @see FileSystem#getPath */ - public static Path get(String path) { - return FileSystems.getDefault().getPath(path); + public static Path get(String first, String... more) { + return FileSystems.getDefault().getPath(first, more); } /** diff --git a/src/share/classes/java/nio/file/SecureDirectoryStream.java b/src/share/classes/java/nio/file/SecureDirectoryStream.java index 319237bfe9694e9d27885659eefac2b4df43de6c..fa26e513fd990a2e01cd595ef1cf69908cdb7ff0 100644 --- a/src/share/classes/java/nio/file/SecureDirectoryStream.java +++ b/src/share/classes/java/nio/file/SecureDirectoryStream.java @@ -43,7 +43,7 @@ import java.io.IOException; * *

A {@code SecureDirectoryStream} requires corresponding support from the * underlying operating system. Where an implementation supports this features - * then the {@code DirectoryStream} returned by the {@link Path#newDirectoryStream + * then the {@code DirectoryStream} returned by the {@link Files#newDirectoryStream * newDirectoryStream} method will be a {@code SecureDirectoryStream} and must * be cast to that type in order to invoke the methods defined by this interface. * @@ -56,20 +56,15 @@ import java.io.IOException; * @since 1.7 */ -public abstract class SecureDirectoryStream - implements DirectoryStream +public interface SecureDirectoryStream + extends DirectoryStream { - /** - * Initialize a new instance of this class. - */ - protected SecureDirectoryStream() { } - /** * Opens the directory identified by the given path, returning a {@code * SecureDirectoryStream} to iterate over the entries in the directory. * *

This method works in exactly the manner specified by the {@link - * Path#newDirectoryStream() newDirectoryStream} method for the case that + * Files#newDirectoryStream(Path) newDirectoryStream} method for the case that * the {@code path} parameter is an {@link Path#isAbsolute absolute} path. * When the parameter is a relative path then the directory to open is * relative to this open directory. The {@link @@ -99,8 +94,7 @@ public abstract class SecureDirectoryStream * installed, the {@link SecurityManager#checkRead(String) checkRead} * method is invoked to check read access to the directory. */ - public abstract SecureDirectoryStream newDirectoryStream(T path, - LinkOption... options) + SecureDirectoryStream newDirectoryStream(T path, LinkOption... options) throws IOException; /** @@ -108,11 +102,11 @@ public abstract class SecureDirectoryStream * channel to access the file. * *

This method works in exactly the manner specified by the {@link - * Path#newByteChannel Path.newByteChannel} method for the + * Files#newByteChannel Files.newByteChannel} method for the * case that the {@code path} parameter is an {@link Path#isAbsolute absolute} * path. When the parameter is a relative path then the file to open or * create is relative to this open directory. In addition to the options - * defined by the {@code Path.newByteChannel} method, the {@link + * defined by the {@code Files.newByteChannel} method, the {@link * LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} option may be used to * ensure that this method fails if the file is a symbolic link. * @@ -149,15 +143,15 @@ public abstract class SecureDirectoryStream * checkWrite} method is invoked to check write access to the path * if the file is opened for writing. */ - public abstract SeekableByteChannel newByteChannel(T path, - Set options, - FileAttribute... attrs) + SeekableByteChannel newByteChannel(T path, + Set options, + FileAttribute... attrs) throws IOException; /** * Deletes a file. * - *

Unlike the {@link Path#delete delete()} method, this method does + *

Unlike the {@link Files#delete delete()} method, this method does * not first examine the file to determine if the file is a directory. * Whether a directory is deleted by this method is system dependent and * therefore not specified. If the file is a symbolic link, then the link @@ -179,12 +173,12 @@ public abstract class SecureDirectoryStream * installed, the {@link SecurityManager#checkDelete(String) checkDelete} * method is invoked to check delete access to the file */ - public abstract void deleteFile(T path) throws IOException; + void deleteFile(T path) throws IOException; /** * Deletes a directory. * - *

Unlike the {@link Path#delete delete()} method, this method + *

Unlike the {@link Files#delete delete()} method, this method * does not first examine the file to determine if the file is a directory. * Whether non-directories are deleted by this method is system dependent and * therefore not specified. When the parameter is a relative path then the @@ -207,12 +201,12 @@ public abstract class SecureDirectoryStream * installed, the {@link SecurityManager#checkDelete(String) checkDelete} * method is invoked to check delete access to the directory */ - public abstract void deleteDirectory(T path) throws IOException; + void deleteDirectory(T path) throws IOException; /** * Move a file from this directory to another directory. * - *

This method works in a similar manner to {@link Path#moveTo moveTo} + *

This method works in a similar manner to {@link Files#move move} * method when the {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} option * is specified. That is, this method moves a file as an atomic file system * operation. If the {@code srcpath} parameter is an {@link Path#isAbsolute @@ -247,7 +241,7 @@ public abstract class SecureDirectoryStream * method is invoked to check write access to both the source and * target file. */ - public abstract void move(T srcpath, SecureDirectoryStream targetdir, T targetpath) + void move(T srcpath, SecureDirectoryStream targetdir, T targetpath) throws IOException; /** @@ -273,7 +267,7 @@ public abstract class SecureDirectoryStream * this directory stream, or {@code null} if the attribute view * type is not available */ - public abstract V getFileAttributeView(Class type); + V getFileAttributeView(Class type); /** * Returns a new file attribute view to access the file attributes of a file @@ -306,7 +300,7 @@ public abstract class SecureDirectoryStream * type is not available * */ - public abstract V getFileAttributeView(T path, - Class type, - LinkOption... options); + V getFileAttributeView(T path, + Class type, + LinkOption... options); } diff --git a/src/share/classes/java/io/TempFileHelper.java b/src/share/classes/java/nio/file/TempFileHelper.java similarity index 56% rename from src/share/classes/java/io/TempFileHelper.java rename to src/share/classes/java/nio/file/TempFileHelper.java index 19852f32d1a49169c2c8dff19d4ecae6f5b79981..377730b4455362db3ad526c997b54b0025a73d1e 100644 --- a/src/share/classes/java/io/TempFileHelper.java +++ b/src/share/classes/java/nio/file/TempFileHelper.java @@ -23,54 +23,82 @@ * questions. */ -package java.io; +package java.nio.file; -import java.nio.file.FileSystems; -import java.nio.file.InvalidPathException; -import java.nio.file.FileAlreadyExistsException; +import java.util.Set; +import java.util.EnumSet; +import java.security.SecureRandom; +import static java.security.AccessController.*; +import java.io.IOException; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; import static java.nio.file.attribute.PosixFilePermission.*; -import java.util.Set; -import java.util.EnumSet; +import sun.security.action.GetPropertyAction; + /** - * Helper class to support creation of temporary files and directory with + * Helper class to support creation of temporary files and directories with * initial attributes. */ class TempFileHelper { private TempFileHelper() { } + // temporary directory location + private static final Path tmpdir = + Paths.get(doPrivileged(new GetPropertyAction("java.io.tmpdir"))); + + private static final boolean isPosix = + FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); + + // file name generation, same as java.io.File for now + private static final SecureRandom random = new SecureRandom(); + private static Path generatePath(String prefix, String suffix, Path dir) { + long n = random.nextLong(); + n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n); + Path name = dir.getFileSystem().getPath(prefix + Long.toString(n) + suffix); + // the generated name should be a simple file name + if (name.getParent() != null) + throw new IllegalArgumentException("Invalid prefix or suffix"); + return dir.resolve(name); + } + // default file and directory permissions (lazily initialized) - private static class PermissionsHolder { - static final boolean hasPosixPermissions = FileSystems.getDefault() - .supportedFileAttributeViews().contains("posix"); + private static class PosixPermissions { static final FileAttribute> filePermissions = PosixFilePermissions.asFileAttribute(EnumSet.of(OWNER_READ, OWNER_WRITE)); - static final FileAttribute> directoryPermissions = + static final FileAttribute> dirPermissions = PosixFilePermissions.asFileAttribute(EnumSet .of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE)); } /** - * Creates a file or directory in the temporary directory. + * Creates a file or directory in in the given given directory (or in the + * temporary directory if dir is {@code null}). */ - private static File create(String prefix, + private static Path create(Path dir, + String prefix, String suffix, - FileAttribute[] attrs, - boolean isDirectory) + boolean createDirectory, + FileAttribute[] attrs) throws IOException { + if (prefix == null) + prefix = ""; + if (suffix == null) + suffix = (createDirectory) ? "" : ".tmp"; + if (dir == null) + dir = tmpdir; + // in POSIX environments use default file and directory permissions // if initial permissions not given by caller. - if (PermissionsHolder.hasPosixPermissions) { + if (isPosix && (dir.getFileSystem() == FileSystems.getDefault())) { if (attrs.length == 0) { // no attributes so use default permissions attrs = new FileAttribute[1]; - attrs[0] = (isDirectory) ? PermissionsHolder.directoryPermissions : - PermissionsHolder.filePermissions; + attrs[0] = (createDirectory) ? PosixPermissions.dirPermissions : + PosixPermissions.filePermissions; } else { // check if posix permissions given; if not use default boolean hasPermissions = false; @@ -84,9 +112,9 @@ class TempFileHelper { FileAttribute[] copy = new FileAttribute[attrs.length+1]; System.arraycopy(attrs, 0, copy, 0, attrs.length); attrs = copy; - attrs[attrs.length-1] = (isDirectory) ? - PermissionsHolder.directoryPermissions : - PermissionsHolder.filePermissions; + attrs[attrs.length-1] = (createDirectory) ? + PosixPermissions.dirPermissions : + PosixPermissions.filePermissions; } } } @@ -94,24 +122,25 @@ class TempFileHelper { // loop generating random names until file or directory can be created SecurityManager sm = System.getSecurityManager(); for (;;) { - File tmpdir = File.TempDirectory.location(); - File f = File.TempDirectory.generateFile(prefix, suffix, tmpdir); + Path f; try { - if (isDirectory) { - f.toPath().createDirectory(attrs); - } else { - f.toPath().createFile(attrs); - } - return f; + f = generatePath(prefix, suffix, dir); } catch (InvalidPathException e) { // don't reveal temporary directory location if (sm != null) throw new IllegalArgumentException("Invalid prefix or suffix"); throw e; + } + try { + if (createDirectory) { + return Files.createDirectory(f, attrs); + } else { + return Files.createFile(f, attrs); + } } catch (SecurityException e) { // don't reveal temporary directory location - if (sm != null) - throw new SecurityException("Unable to create temporary file"); + if (dir == tmpdir && sm != null) + throw new SecurityException("Unable to create temporary file or directory"); throw e; } catch (FileAlreadyExistsException e) { // ignore @@ -120,20 +149,27 @@ class TempFileHelper { } /** - * Creates a file in the temporary directory. + * Creates a temporary file in the given directory, or in in the + * temporary directory if dir is {@code null}. */ - static File createFile(String prefix, String suffix, FileAttribute[] attrs) + static Path createTempFile(Path dir, + String prefix, + String suffix, + FileAttribute[] attrs) throws IOException { - return create(prefix, suffix, attrs, false); + return create(dir, prefix, suffix, false, attrs); } /** - * Creates a directory in the temporary directory. + * Creates a temporary directory in the given directory, or in in the + * temporary directory if dir is {@code null}. */ - static File createDirectory(String prefix, FileAttribute[] attrs) + static Path createTempDirectory(Path dir, + String prefix, + FileAttribute[] attrs) throws IOException { - return create(prefix, "", attrs, true); + return create(dir, prefix, null, true, attrs); } } diff --git a/src/share/classes/java/nio/file/WatchEvent.java b/src/share/classes/java/nio/file/WatchEvent.java index 68c93a117a47ba42a189851e80ba68dcea8d3b3e..2753fb2c3ac092ddd8e3246c00095d0ad01683e2 100644 --- a/src/share/classes/java/nio/file/WatchEvent.java +++ b/src/share/classes/java/nio/file/WatchEvent.java @@ -44,7 +44,7 @@ package java.nio.file; * @since 1.7 */ -public abstract class WatchEvent { +public interface WatchEvent { /** * An event kind, for the purposes of identification. @@ -64,11 +64,6 @@ public abstract class WatchEvent { Class type(); } - /** - * Initializes a new instance of this class. - */ - protected WatchEvent() { } - /** * An event modifier that qualifies how a {@link Watchable} is registered * with a {@link WatchService}. @@ -90,7 +85,7 @@ public abstract class WatchEvent { * * @return the event kind */ - public abstract Kind kind(); + Kind kind(); /** * Returns the event count. If the event count is greater than {@code 1} @@ -98,7 +93,7 @@ public abstract class WatchEvent { * * @return the event count */ - public abstract int count(); + int count(); /** * Returns the context for the event. @@ -112,5 +107,5 @@ public abstract class WatchEvent { * * @return the event context; may be {@code null} */ - public abstract T context(); + T context(); } diff --git a/src/share/classes/java/nio/file/WatchKey.java b/src/share/classes/java/nio/file/WatchKey.java index 72997866b20b278c4c16a694f99c434b771cf65f..23897dba4543484875bd1d03d72e8f7a219c326d 100644 --- a/src/share/classes/java/nio/file/WatchKey.java +++ b/src/share/classes/java/nio/file/WatchKey.java @@ -81,11 +81,7 @@ import java.util.List; * @since 1.7 */ -public abstract class WatchKey { - /** - * Initializes a new instance of this class. - */ - protected WatchKey() { } +public interface WatchKey { /** * Tells whether or not this watch key is valid. @@ -95,7 +91,7 @@ public abstract class WatchKey { * * @return {@code true} if, and only if, this watch key is valid */ - public abstract boolean isValid(); + boolean isValid(); /** * Retrieves and removes all pending events for this watch key, returning @@ -105,7 +101,7 @@ public abstract class WatchKey { * * @return the list of the events retrieved; may be empty */ - public abstract List> pollEvents(); + List> pollEvents(); /** * Resets this watch key. @@ -121,7 +117,7 @@ public abstract class WatchKey { * {@code false} if the watch key could not be reset because it is * no longer {@link #isValid valid} */ - public abstract boolean reset(); + boolean reset(); /** * Cancels the registration with the watch service. Upon return the watch key @@ -134,5 +130,21 @@ public abstract class WatchKey { *

If this watch key has already been cancelled then invoking this * method has no effect. Once cancelled, a watch key remains forever invalid. */ - public abstract void cancel(); + void cancel(); + + /** + * Returns the object for which this watch key was created. This method will + * continue to return the object even after the key is cancelled. + * + *

As the {@code WatchService} is intended to map directly on to the + * native file event notification facility (where available) then many of + * details on how registered objects are watched is highly implementation + * specific. When watching a directory for changes for example, and the + * directory is moved or renamed in the file system, there is no guarantee + * that the watch key will be cancelled and so the object returned by this + * method may no longer be a valid path to the directory. + * + * @return the object for which this watch key was created + */ + //T watchable(); } diff --git a/src/share/classes/java/nio/file/WatchService.java b/src/share/classes/java/nio/file/WatchService.java index 048472b6cdb0fdd650e88b1504cf8345686edb0e..255e03fe51880b1e13edefaca98796d8371c6588 100644 --- a/src/share/classes/java/nio/file/WatchService.java +++ b/src/share/classes/java/nio/file/WatchService.java @@ -103,13 +103,9 @@ import java.util.concurrent.TimeUnit; * @see FileSystem#newWatchService */ -public abstract class WatchService - implements Closeable +public interface WatchService + extends Closeable { - /** - * Initializes a new instance of this class. - */ - protected WatchService() { } /** * Closes this watch service. @@ -129,7 +125,7 @@ public abstract class WatchService * if an I/O error occurs */ @Override - public abstract void close() throws IOException; + void close() throws IOException; /** * Retrieves and removes the next watch key, or {@code null} if none are @@ -140,7 +136,7 @@ public abstract class WatchService * @throws ClosedWatchServiceException * if this watch service is closed */ - public abstract WatchKey poll(); + WatchKey poll(); /** * Retrieves and removes the next watch key, waiting if necessary up to the @@ -160,7 +156,7 @@ public abstract class WatchService * @throws InterruptedException * if interrupted while waiting */ - public abstract WatchKey poll(long timeout, TimeUnit unit) + WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException; /** @@ -174,5 +170,5 @@ public abstract class WatchService * @throws InterruptedException * if interrupted while waiting */ - public abstract WatchKey take() throws InterruptedException; + WatchKey take() throws InterruptedException; } diff --git a/src/share/classes/java/nio/file/attribute/AclEntry.java b/src/share/classes/java/nio/file/attribute/AclEntry.java index b49944c1894c65d969998045c4b145e71cb9efdc..a0ea1fd16d5f5369c9b0d9109c562bd7c570f2cd 100644 --- a/src/share/classes/java/nio/file/attribute/AclEntry.java +++ b/src/share/classes/java/nio/file/attribute/AclEntry.java @@ -176,7 +176,7 @@ public final class AclEntry { */ public Builder setPermissions(Set perms) { // copy and check for erroneous elements - perms = new HashSet(perms); + perms = EnumSet.copyOf(perms); checkSet(perms, AclEntryPermission.class); this.perms = perms; return this; @@ -190,8 +190,7 @@ public final class AclEntry { * @return this builder */ public Builder setPermissions(AclEntryPermission... perms) { - Set set = - new HashSet(perms.length); + Set set = EnumSet.noneOf(AclEntryPermission.class); // copy and check for null elements for (AclEntryPermission p: perms) { if (p == null) @@ -214,7 +213,7 @@ public final class AclEntry { */ public Builder setFlags(Set flags) { // copy and check for erroneous elements - flags = new HashSet(flags); + flags = EnumSet.copyOf(flags); checkSet(flags, AclEntryFlag.class); this.flags = flags; return this; @@ -228,7 +227,7 @@ public final class AclEntry { * @return this builder */ public Builder setFlags(AclEntryFlag... flags) { - Set set = new HashSet(flags.length); + Set set = EnumSet.noneOf(AclEntryFlag.class); // copy and check for null elements for (AclEntryFlag f: flags) { if (f == null) diff --git a/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java b/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java index 136731166238d8cb9a5ea4d68e7381be7d1a2aef..d4a8ba8b27ed482b94fee3db56d8447ab2dfbaa0 100644 --- a/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java +++ b/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java @@ -65,7 +65,7 @@ import java.io.IOException; * UserPrincipalLookupService} may be used to obtain a {@link UserPrincipal} * to represent these special identities by invoking the {@link * UserPrincipalLookupService#lookupPrincipalByName lookupPrincipalByName} - * method. + * method.

* *

Usage Example: * Suppose we wish to add an entry to an existing ACL to grant "joe" access: @@ -75,7 +75,7 @@ import java.io.IOException; * .lookupPrincipalByName("joe"); * * // get view - * AclFileAttributeView view = file.getFileAttributeView(AclFileAttributeView.class); + * AclFileAttributeView view = Files.getFileAttributeView(file, AclFileAttributeView.class); * * // create ACE to give "joe" read access * AclEntry entry = AclEntry.newBuilder() @@ -110,11 +110,11 @@ import java.io.IOException; * * * - *

The {@link FileRef#getAttribute getAttribute} method may be used to read + *

The {@link Files#getAttribute getAttribute} method may be used to read * the ACL or owner attributes as if by invoking the {@link #getAcl getAcl} or * {@link #getOwner getOwner} methods. * - *

The {@link FileRef#setAttribute setAttribute} method may be used to + *

The {@link Files#setAttribute setAttribute} method may be used to * update the ACL or owner attributes as if by invoking the {@link #setAcl setAcl} * or {@link #setOwner setOwner} methods. * @@ -122,8 +122,8 @@ import java.io.IOException; * *

Implementations supporting this attribute view may also support setting * the initial ACL when creating a file or directory. The initial ACL - * may be provided to methods such as {@link Path#createFile createFile} or {@link - * Path#createDirectory createDirectory} as an {@link FileAttribute} with {@link + * may be provided to methods such as {@link Files#createFile createFile} or {@link + * Files#createDirectory createDirectory} as an {@link FileAttribute} with {@link * FileAttribute#name name} {@code "acl:acl"} and a {@link FileAttribute#value * value} that is the list of {@code AclEntry} objects. * @@ -135,8 +135,6 @@ import java.io.IOException; * translation. * * @since 1.7 - * @see Attributes#getAcl - * @see Attributes#setAcl */ public interface AclFileAttributeView diff --git a/src/share/classes/java/nio/file/attribute/Attributes.java b/src/share/classes/java/nio/file/attribute/Attributes.java deleted file mode 100644 index 32dbec38ee602a63518a82debe409a78f123f67b..0000000000000000000000000000000000000000 --- a/src/share/classes/java/nio/file/attribute/Attributes.java +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (c) 2007, 2009, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.nio.file.attribute; - -import java.nio.file.*; -import java.io.IOException; -import java.util.*; - -/** - * This class consists exclusively of static methods that operate on or return - * the attributes of files or file stores. These methods provide for convenient - * use of the {@link AttributeView attribute-views} defined in this package. - * - * @since 1.7 - */ - -public final class Attributes { - private Attributes() { } - - /** - * Reads the basic file attributes of a file. - * - *

The {@code options} array may be used to indicate how symbolic links - * are handled for the case that the file is a symbolic link. By default, - * symbolic links are followed and the file attributes of the final target - * of the link are read. If the option {@link LinkOption#NOFOLLOW_LINKS - * NOFOLLOW_LINKS} is present then symbolic links are not followed and so - * the method returns the file attributes of the symbolic link itself. - * This option should be used where there is a need to determine if a - * file is a symbolic link: - *

-     *    boolean isSymbolicLink = Attributes.readBasicFileAttributes(file, NOFOLLOW_LINKS).isSymbolicLink();
-     * 
- * - *

It is implementation specific if all file attributes are read as an - * atomic operation with respect to other file system operations. - * - * @param file - * A file reference that locates the file - * @param options - * Options indicating how symbolic links are handled - * - * @return The basic file attributes - * - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, the security manager's {@link - * SecurityManager#checkRead(String) checkRead} method is invoked - * to check read access to file - * - * @see BasicFileAttributeView#readAttributes - */ - public static BasicFileAttributes readBasicFileAttributes(FileRef file, - LinkOption... options) - throws IOException - { - return file.getFileAttributeView(BasicFileAttributeView.class, options) - .readAttributes(); - } - - /** - * Reads the POSIX file attributes of a file. - * - *

The {@code file} parameter locates a file that supports the {@link - * PosixFileAttributeView}. This file attribute view provides access to a - * subset of the file attributes commonly associated with files on file - * systems used by operating systems that implement the Portable Operating - * System Interface (POSIX) family of standards. It is implementation - * specific if all file attributes are read as an atomic operation with - * respect to other file system operations. - * - *

The {@code options} array may be used to indicate how symbolic links - * are handled for the case that the file is a symbolic link. By default, - * symbolic links are followed and the file attributes of the final target - * of the link are read. If the option {@link LinkOption#NOFOLLOW_LINKS - * NOFOLLOW_LINKS} is present then symbolic links are not followed and so - * the method returns the file attributes of the symbolic link itself. - * - * @param file - * A file reference that locates the file - * @param options - * Options indicating how symbolic links are handled - * - * @return The POSIX file attributes - * - * @throws UnsupportedOperationException - * If the {@code PosixFileAttributeView} is not available - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, it denies {@link RuntimePermission}("accessUserInformation") - * or its {@link SecurityManager#checkRead(String) checkRead} method - * denies read access to the file. - * - * @see PosixFileAttributeView#readAttributes - */ - public static PosixFileAttributes readPosixFileAttributes(FileRef file, - LinkOption... options) - throws IOException - { - PosixFileAttributeView view = - file.getFileAttributeView(PosixFileAttributeView.class, options); - if (view == null) - throw new UnsupportedOperationException(); - return view.readAttributes(); - } - - /** - * Reads the DOS file attributes of a file. - * - *

The {@code file} parameter locates a file that supports the {@link - * DosFileAttributeView}. This file attribute view provides access to - * legacy "DOS" attributes supported by the file systems such as File - * Allocation Table (FAT), commonly used in consumer devices. It is - * implementation specific if all file attributes are read as an atomic - * operation with respect to other file system operations. - * - *

The {@code options} array may be used to indicate how symbolic links - * are handled for the case that the file is a symbolic link. By default, - * symbolic links are followed and the file attributes of the final target - * of the link are read. If the option {@link LinkOption#NOFOLLOW_LINKS - * NOFOLLOW_LINKS} is present then symbolic links are not followed and so - * the method returns the file attributes of the symbolic link itself. - * - * @param file - * A file reference that locates the file - * @param options - * Options indicating how symbolic links are handled - * - * @return The DOS file attributes - * - * @throws UnsupportedOperationException - * If the {@code DosFileAttributeView} is not available - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, the security manager's {@link - * SecurityManager#checkRead(String) checkRead} method is invoked - * to check read access to file - * - * @see DosFileAttributeView#readAttributes - */ - public static DosFileAttributes readDosFileAttributes(FileRef file, - LinkOption... options) - throws IOException - { - DosFileAttributeView view = - file.getFileAttributeView(DosFileAttributeView.class, options); - if (view == null) - throw new UnsupportedOperationException(); - return view.readAttributes(); - } - - /** - * Returns the owner of a file. - * - *

The {@code file} parameter locates a file that supports the {@link - * FileOwnerAttributeView}. This file attribute view provides access to - * a file attribute that is the owner of the file. - * - * @param file - * A file reference that locates the file - * - * @return A user principal representing the owner of the file - * - * @throws UnsupportedOperationException - * If the {@code FileOwnerAttributeView} is not available - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, it denies {@link RuntimePermission}("accessUserInformation") - * or its {@link SecurityManager#checkRead(String) checkRead} method - * denies read access to the file. - * - * @see FileOwnerAttributeView#getOwner - */ - public static UserPrincipal getOwner(FileRef file) throws IOException { - FileOwnerAttributeView view = - file.getFileAttributeView(FileOwnerAttributeView.class); - if (view == null) - throw new UnsupportedOperationException(); - return view.getOwner(); - } - - /** - * Updates the file owner. - * - *

The {@code file} parameter locates a file that supports the {@link - * FileOwnerAttributeView}. This file attribute view provides access to - * a file attribute that is the owner of the file. - * - * @param file - * A file reference that locates the file - * @param owner - * The new file owner - * - * @throws UnsupportedOperationException - * If the {@code FileOwnerAttributeView} is not available - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, it denies {@link RuntimePermission}("accessUserInformation") - * or its {@link SecurityManager#checkWrite(String) checkWrite} - * method denies write access to the file. - * - * @see FileOwnerAttributeView#setOwner - */ - public static void setOwner(FileRef file, UserPrincipal owner) - throws IOException - { - FileOwnerAttributeView view = - file.getFileAttributeView(FileOwnerAttributeView.class); - if (view == null) - throw new UnsupportedOperationException(); - view.setOwner(owner); - } - - /** - * Reads a file's Access Control List (ACL). - * - *

The {@code file} parameter locates a file that supports the {@link - * AclFileAttributeView}. This file attribute view provides access to ACLs - * based on the ACL model specified in - * RFC 3530. - * - * @param file - * A file reference that locates the file - * - * @return An ordered list of {@link AclEntry entries} representing the - * ACL. The returned list is modifiable. - * - * @throws UnsupportedOperationException - * If the {@code AclAttributeView} is not available - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, it denies {@link RuntimePermission}("accessUserInformation") - * or its {@link SecurityManager#checkRead(String) checkRead} method - * denies read access to the file. - * - * @see AclFileAttributeView#getAcl - */ - public static List getAcl(FileRef file) throws IOException { - AclFileAttributeView view = - file.getFileAttributeView(AclFileAttributeView.class); - if (view == null) - throw new UnsupportedOperationException(); - return view.getAcl(); - } - - /** - * Updates a file's Access Control List (ACL). - * - *

The {@code file} parameter locates a file that supports the {@link - * AclFileAttributeView}. This file attribute view provides access to ACLs - * based on the ACL model specified in - * RFC 3530. - * - * @param file - * A file reference that locates the file - * @param acl - * The new file ACL - * - * @throws UnsupportedOperationException - * If the {@code AclFileAttributeView} is not available - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, it denies {@link RuntimePermission}("accessUserInformation") - * or its {@link SecurityManager#checkWrite(String) checkWrite} - * method denies write access to the file. - * - * @see AclFileAttributeView#setAcl - */ - public static void setAcl(FileRef file, List acl) - throws IOException - { - AclFileAttributeView view = - file.getFileAttributeView(AclFileAttributeView.class); - if (view == null) - throw new UnsupportedOperationException(); - view.setAcl(acl); - } - - /** - * Updates a file's last modified time attribute. The file time is converted - * to the epoch and precision supported by the file system. Converting from - * finer to coarser granularities result in precision loss. The behavior of - * this method when attempting to set a timestamp to a value that is outside - * the range supported by the underlying file store is not defined. It may - * or not fail by throwing an {@code IOException}. - * - *

If the file system does not support a last modified time attribute - * then this method has no effect. - * - *

Usage Example: - * Suppose we want to set the last modified time to the current time: - *

-     *    FileTime now = FileTime.fromMillis(System.currentTimeMillis());
-     *    Attributes.setLastModifiedTime(file, now);
-     * 
- * - * @param file - * A file reference that locates the file - * @param lastModifiedTime - * The new last modified time - * - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, the security manager's {@link - * SecurityManager#checkWrite(String) checkWrite} method is invoked - * to check write access to file - * - * @see BasicFileAttributeView#setTimes - */ - public static void setLastModifiedTime(FileRef file, - FileTime lastModifiedTime) - throws IOException - { - if (lastModifiedTime == null) - throw new NullPointerException("'lastModifiedTime' is null"); - file.getFileAttributeView(BasicFileAttributeView.class) - .setTimes(lastModifiedTime, null, null); - } - - /** - * Updates a file's last access time attribute. The file time is converted - * to the epoch and precision supported by the file system. Converting from - * finer to coarser granularities result in precision loss. The behavior of - * this method when attempting to set a timestamp to a value that is outside - * the range supported by the underlying file store is not defined. It may - * or not fail by throwing an {@code IOException}. - * - *

If the file system does not support a last access time attribute then - * this method has no effect. - * - * @param file - * A file reference that locates the file - * @param lastAccessTime - * The new last access time - * - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, the security manager's {@link - * SecurityManager#checkWrite(String) checkWrite} method is invoked - * to check write access to file - * - * @see BasicFileAttributeView#setTimes - */ - public static void setLastAccessTime(FileRef file, - FileTime lastAccessTime) - throws IOException - { - if (lastAccessTime == null) - throw new NullPointerException("'lastAccessTime' is null"); - file.getFileAttributeView(BasicFileAttributeView.class) - .setTimes(null, lastAccessTime, null); - } - - /** - * Sets a file's POSIX permissions. - * - *

The {@code file} parameter is a reference to an existing file. It - * supports the {@link PosixFileAttributeView} that provides access to file - * attributes commonly associated with files on file systems used by - * operating systems that implement the Portable Operating System Interface - * (POSIX) family of standards. - * - * @param file - * A file reference that locates the file - * @param perms - * The new set of permissions - * - * @throws UnsupportedOperationException - * If {@code PosixFileAttributeView} is not available - * @throws ClassCastException - * If the sets contains elements that are not of type {@code - * PosixFilePermission} - * @throws IOException - * If an I/O error occurs - * @throws SecurityException - * In the case of the default provider, and a security manager is - * installed, it denies {@link RuntimePermission}("accessUserInformation") - * or its {@link SecurityManager#checkWrite(String) checkWrite} - * method denies write access to the file. - * - * @see PosixFileAttributeView#setPermissions - */ - public static void setPosixFilePermissions(FileRef file, - Set perms) - throws IOException - { - PosixFileAttributeView view = - file.getFileAttributeView(PosixFileAttributeView.class); - if (view == null) - throw new UnsupportedOperationException(); - view.setPermissions(perms); - } - - /** - * Reads the space attributes of a file store. - * - *

The {@code store} parameter is a file store that supports the - * {@link FileStoreSpaceAttributeView} providing access to the space related - * attributes of the file store. It is implementation specific if all attributes - * are read as an atomic operation with respect to other file system operations. - * - * @param store - * The file store - * - * @return The file store space attributes - * - * @throws UnsupportedOperationException - * If the file store space attribute view is not supported - * @throws IOException - * If an I/O error occurs - * - * @see FileStoreSpaceAttributeView#readAttributes() - */ - public static FileStoreSpaceAttributes readFileStoreSpaceAttributes(FileStore store) - throws IOException - { - FileStoreSpaceAttributeView view = - store.getFileStoreAttributeView(FileStoreSpaceAttributeView.class); - if (view == null) - throw new UnsupportedOperationException(); - return view.readAttributes(); - } -} diff --git a/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java b/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java index e2534812e99c2b54b97a00b95bffb4c7e208c924..4c50f82e9526f705099553272d2eb32330453797 100644 --- a/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java +++ b/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java @@ -85,16 +85,15 @@ import java.io.IOException; * * * - *

The {@link java.nio.file.FileRef#getAttribute getAttribute} method may be + *

The {@link java.nio.file.Files#getAttribute getAttribute} method may be * used to read any of these attributes as if by invoking the {@link * #readAttributes() readAttributes()} method. * - *

The {@link java.nio.file.FileRef#setAttribute setAttribute} method may be + *

The {@link java.nio.file.Files#setAttribute setAttribute} method may be * used to update the file's last modified time, last access time or create time * attributes as if by invoking the {@link #setTimes setTimes} method. * * @since 1.7 - * @see Attributes */ public interface BasicFileAttributeView @@ -131,9 +130,10 @@ public interface BasicFileAttributeView *

This method updates the file's timestamp attributes. The values are * converted to the epoch and precision supported by the file system. * Converting from finer to coarser granularities result in precision loss. - * The behavior of this method when attempting to set a timestamp to a value - * that is outside the range supported by the underlying file store is not - * defined. It may or not fail by throwing an {@code IOException}. + * The behavior of this method when attempting to set a timestamp that is + * not supported or to a value that is outside the range supported by the + * underlying file store is not defined. It may or not fail by throwing an + * {@code IOException}. * *

If any of the {@code lastModifiedTime}, {@code lastAccessTime}, * or {@code createTime} parameters has the value {@code null} then the @@ -146,6 +146,14 @@ public interface BasicFileAttributeView * lastAccessTime} and {@code createTime} parameters are {@code null} then * this method has no effect. * + *

Usage Example: + * Suppose we want to change a file's creation time. + *

+     *    Path path = ...
+     *    FileTime time = ...
+     *    Files.getFileAttributeView(path, BasicFileAttributeView.class).setTimes(null, null, time);
+     * 
+ * * @param lastModifiedTime * the new last modified time, or {@code null} to not change the * value @@ -160,6 +168,8 @@ public interface BasicFileAttributeView * In the case of the default provider, a security manager is * installed, its {@link SecurityManager#checkWrite(String) checkWrite} * method is invoked to check write access to the file + * + * @see java.nio.file.Files#setLastModifiedTime */ void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, diff --git a/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java b/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java index 31e076b9286a8851225924b4b003505652822ece..aa5d2f56156c0eccfe0edbb60b52cb2d6fb50841 100644 --- a/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java +++ b/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java @@ -34,8 +34,8 @@ package java.nio.file.attribute; * *

Usage Example: *

- *    FileRef file = ...
- *    BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file);
+ *    Path file = ...
+ *    BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class);
  * 
* * @since 1.7 @@ -48,25 +48,40 @@ public interface BasicFileAttributes { /** * Returns the time of last modification. * + *

If the file system implementation does not support a time stamp + * to indicate the time of last modification then this method returns an + * implementation specific default value, typically a {@code FileTime} + * representing the epoch (1970-01-01T00:00:00Z). + * * @return a {@code FileTime} representing the time the file was last - * modified or {@code null} if the attribute is not supported. + * modified */ FileTime lastModifiedTime(); /** - * Returns the time of last access if supported. + * Returns the time of last access. + * + *

If the file system implementation does not support a time stamp + * to indicate the time of last access then this method returns + * an implementation specific default value, typically the {@link + * #lastModifiedTime() last-modified-time} or a {@code FileTime} + * representing the epoch (1970-01-01T00:00:00Z). * - * @return a {@code FileTime} representing the time of last access or - * {@code null} if the attribute is not supported. + * @return a {@code FileTime} representing the time of last access */ FileTime lastAccessTime(); /** - * Returns the creation time if supported. The creation time is the time - * that the file was created. + * Returns the creation time. The creation time is the time that the file + * was created. + * + *

If the file system implementation does not support a time stamp + * to indicate the time when the file was created then this method returns + * an implementation specific default value, typically the {@link + * #lastModifiedTime() last-modified-time} or a {@code FileTime} + * representing the epoch (1970-01-01T00:00:00Z). * - * @return a {@code FileTime} representing the time the file was created - * or {@code null} if the attribute is not supported. + * @return a {@code FileTime} representing the time the file was created */ FileTime creationTime(); @@ -120,7 +135,7 @@ public interface BasicFileAttributes { * *

File keys returned by this method can be compared for equality and are * suitable for use in collections. If the file system and files remain static, - * and two files are the {@link java.nio.file.Path#isSameFile same} with + * and two files are the {@link java.nio.file.Files#isSameFile same} with * non-{@code null} file keys, then their file keys are equal. * * @see java.nio.file.Files#walkFileTree diff --git a/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java b/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java index def09013e78dd30bb40d824c183fe74564da331c..7a21bae5fec8124d643bf69b4ff4b28cf56b870e 100644 --- a/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java +++ b/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java @@ -65,12 +65,12 @@ import java.io.IOException; * * * - *

The {@link java.nio.file.FileRef#getAttribute getAttribute} method may + *

The {@link java.nio.file.Files#getAttribute getAttribute} method may * be used to read any of these attributes, or any of the attributes defined by * {@link BasicFileAttributeView} as if by invoking the {@link #readAttributes * readAttributes()} method. * - *

The {@link java.nio.file.FileRef#setAttribute setAttribute} method may + *

The {@link java.nio.file.Files#setAttribute setAttribute} method may * be used to update the file's last modified time, last access time or create * time attributes as defined by {@link BasicFileAttributeView}. It may also be * used to update the DOS attributes as if by invoking the {@link #setReadOnly diff --git a/src/share/classes/java/nio/file/attribute/DosFileAttributes.java b/src/share/classes/java/nio/file/attribute/DosFileAttributes.java index d8d22174e84b574b4acfc08b5ff3ae59e8555d19..d095d213358b3179b269fd88bb18688a03d4ffe0 100644 --- a/src/share/classes/java/nio/file/attribute/DosFileAttributes.java +++ b/src/share/classes/java/nio/file/attribute/DosFileAttributes.java @@ -29,13 +29,13 @@ package java.nio.file.attribute; * File attributes associated with a file in a file system that supports * legacy "DOS" attributes. * - *

The DOS attributes of a file are retrieved using a {@link - * DosFileAttributeView} by invoking its {@link DosFileAttributeView#readAttributes - * readAttributes} method. + *

Usage Example: + *

+ *    Path file = ...
+ *    DosFileAttributes attrs = Files.readAttributes(file, DosFileAttributes.class);
+ * 
* * @since 1.7 - * - * @see Attributes#readDosFileAttributes */ public interface DosFileAttributes diff --git a/src/share/classes/java/nio/file/attribute/FileAttribute.java b/src/share/classes/java/nio/file/attribute/FileAttribute.java index d8c32fd7bbeb6f912815ca4e0b85881f80c48880..cd11d43dde8b67071e960e51e10f0bb5d953a6b3 100644 --- a/src/share/classes/java/nio/file/attribute/FileAttribute.java +++ b/src/share/classes/java/nio/file/attribute/FileAttribute.java @@ -28,8 +28,8 @@ package java.nio.file.attribute; /** * An object that encapsulates the value of a file attribute that can be set * atomically when creating a new file or directory by invoking the {@link - * java.nio.file.Path#createFile createFile} or {@link - * java.nio.file.Path#createDirectory createDirectory} methods. + * java.nio.file.Files#createFile createFile} or {@link + * java.nio.file.Files#createDirectory createDirectory} methods. * * @param The type of the file attribute value * diff --git a/src/share/classes/java/nio/file/attribute/FileAttributeView.java b/src/share/classes/java/nio/file/attribute/FileAttributeView.java index c9d7327494e8d745c45327d29ed09ba8224add34..ee90ba07dba1c063a18e4db7b94ede1fab5efef7 100644 --- a/src/share/classes/java/nio/file/attribute/FileAttributeView.java +++ b/src/share/classes/java/nio/file/attribute/FileAttributeView.java @@ -33,7 +33,7 @@ package java.nio.file.attribute; * * @since 1.7 * - * @see java.nio.file.FileRef#getFileAttributeView(Class,java.nio.file.LinkOption[]) + * @see java.nio.file.Files#getFileAttributeView(Path,Class,java.nio.file.LinkOption[]) */ public interface FileAttributeView diff --git a/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java b/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java index 8bf3a0932eb6f6411e470956ce920b37fdc713f5..09bc7ca02d6112f63072893317f99501d9198a69 100644 --- a/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java +++ b/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java @@ -37,8 +37,8 @@ import java.io.IOException; *

The {@link #getOwner getOwner} or {@link #setOwner setOwner} methods may * be used to read or update the owner of the file. * - *

The {@link java.nio.file.FileRef#getAttribute getAttribute} and - * {@link java.nio.file.FileRef#setAttribute setAttribute} methods may also be + *

The {@link java.nio.file.Files#getAttribute getAttribute} and + * {@link java.nio.file.Files#setAttribute setAttribute} methods may also be * used to read or update the owner. In that case, the owner attribute is * identified by the name {@code "owner"}, and the value of the attribute is * a {@link UserPrincipal}. diff --git a/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributeView.java b/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributeView.java deleted file mode 100644 index dca8d4f010c1690ed48e9ef2f34dce88269f0407..0000000000000000000000000000000000000000 --- a/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributeView.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2007, 2009, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.nio.file.attribute; - -import java.io.IOException; - -/** - * A file store attribute view that supports reading of space attributes. - * - *

Where dynamic access to file attributes is required, the attributes - * supported by this attribute view have the following names and types: - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Name Type
"totalSpace" {@link Long}
"usableSpace" {@link Long}
"unallocatedSpace" {@link Long}
- *
- *

The {@link java.nio.file.FileStore#getAttribute getAttribute} method may - * be used to read any of these attributes. - * - * @since 1.7 - */ - -public interface FileStoreSpaceAttributeView - extends FileStoreAttributeView -{ - /** - * Returns the name of the attribute view. Attribute views of this type - * have the name {@code "space"}. - */ - @Override - String name(); - - /** - * Reads the disk space attributes as a bulk operation. - * - *

It is file system specific if all attributes are read as an - * atomic operation with respect to other file system operations. - * - * @return The disk space attributes - * - * @throws IOException - * If an I/O error occurs - */ - FileStoreSpaceAttributes readAttributes() throws IOException; -} diff --git a/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributes.java b/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributes.java deleted file mode 100644 index ff2bfb66f61f9acfb495dd820151b2c2b8f07da9..0000000000000000000000000000000000000000 --- a/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributes.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2007, 2009, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package java.nio.file.attribute; - -/** - * Space related attributes of a file store. - * - * @since 1.7 - * - * @see Attributes#readFileStoreSpaceAttributes - */ - -public interface FileStoreSpaceAttributes { - /** - * Returns the size, in bytes, of the file store. - */ - long totalSpace(); - - /** - * Returns the number of bytes available to this Java virtual machine on the - * file store. - * - *

The returned number of available bytes is a hint, but not a - * guarantee, that it is possible to use most or any of these bytes. The - * number of usable bytes is most likely to be accurate immediately - * after the space attributes are obtained. It is likely to be made inaccurate - * by any external I/O operations including those made on the system outside - * of this Java virtual machine. - */ - long usableSpace(); - - /** - * Returns the number of unallocated bytes in the file store. - * - *

The returned number of unallocated bytes is a hint, but not a - * guarantee, that it is possible to use most or any of these bytes. The - * number of unallocated bytes is most likely to be accurate immediately - * after the space attributes are obtained. It is likely to be - * made inaccurate by any external I/O operations including those made on - * the system outside of this virtual machine. - */ - long unallocatedSpace(); -} diff --git a/src/share/classes/java/nio/file/attribute/FileTime.java b/src/share/classes/java/nio/file/attribute/FileTime.java index 1b3d2ff2f84014cd2fcca2e888de52a563c4fb15..6cac437cdcef92b42732c6ae8bbf3bfe026a50e0 100644 --- a/src/share/classes/java/nio/file/attribute/FileTime.java +++ b/src/share/classes/java/nio/file/attribute/FileTime.java @@ -35,20 +35,53 @@ import java.util.concurrent.TimeUnit; /** * Represents the value of a file's time stamp attribute. For example, it may - * represent the time that the file was last modified, accessed, or created. + * represent the time that the file was last + * {@link BasicFileAttributes#lastModifiedTime() modified}, + * {@link BasicFileAttributes#lastAccessTime() accessed}, + * or {@link BasicFileAttributes#creationTime() created}. * *

Instances of this class are immutable. * * @since 1.7 - * @see BasicFileAttributes - * @see Attributes#setLastModifiedTime + * @see java.nio.file.Files#setLastModifiedTime + * @see java.nio.file.Files#getLastModifiedTime */ -public final class FileTime implements Comparable { +public final class FileTime + implements Comparable +{ + /** + * The value since the epoch; can be negative. + */ private final long value; + + /** + * The unit of granularity to interpret the value. + */ private final TimeUnit unit; - private String valueAsString; // created lazily + /** + * The value return by toString (created lazily) + */ + private String valueAsString; + + /** + * The value in days and excess nanos (created lazily) + */ + private DaysAndNanos daysAndNanos; + + /** + * Returns a DaysAndNanos object representing the value. + */ + private DaysAndNanos asDaysAndNanos() { + if (daysAndNanos == null) + daysAndNanos = new DaysAndNanos(value, unit); + return daysAndNanos; + } + + /** + * Initializes a new instance of this class. + */ private FileTime(long value, TimeUnit unit) { if (unit == null) throw new NullPointerException(); @@ -143,9 +176,8 @@ public final class FileTime implements Comparable { */ @Override public int hashCode() { - // hash value for fixed granularity to satisfy contract with equals - long ms = toMillis(); - return (int)(ms ^ (ms >>> 32)); + // hashcode of days/nanos representation to satisfy contract with equals + return asDaysAndNanos().hashCode(); } /** @@ -162,46 +194,12 @@ public final class FileTime implements Comparable { @Override public int compareTo(FileTime other) { // same granularity - if (unit == other.unit) + if (unit == other.unit) { return (value < other.value) ? -1 : (value == other.value ? 0 : 1); - - // compare in days - long thisValueInDays = unit.toDays(value); - long otherValueInDays = other.unit.toDays(other.value); - if (thisValueInDays != otherValueInDays) - return (thisValueInDays < otherValueInDays) ? -1 : 1; - - // compare remainder in nanoseconds - long thisRemainder = remainderInNanos(thisValueInDays); - long otherRemainder = other.remainderInNanos(otherValueInDays); - return (thisRemainder < otherRemainder) ? -1 : - (thisRemainder == otherRemainder) ? 0 : 1; - } - - private long remainderInNanos(long days) { - // constants for conversion - final long C0 = 1L; - final long C1 = C0 * 24L; - final long C2 = C1 * 60L; - final long C3 = C2 * 60L; - final long C4 = C3 * 1000L; - final long C5 = C4 * 1000L; - final long C6 = C5 * 1000L; - - long scale; - switch (unit) { - case DAYS : scale = C0; break; - case HOURS : scale = C1; break; - case MINUTES : scale = C2; break; - case SECONDS : scale = C3; break; - case MILLISECONDS : scale = C4; break; - case MICROSECONDS : scale = C5; break; - case NANOSECONDS : scale = C6; break; - default: - throw new AssertionError("Unit not handled"); + } else { + // compare using days/nanos representation when unit differs + return asDaysAndNanos().compareTo(other.asDaysAndNanos()); } - long rem = value - (days * scale); - return unit.toNanos(rem); } /** @@ -239,26 +237,12 @@ public final class FileTime implements Comparable { // nothing to do when seconds/minutes/hours/days String fractionAsString = ""; if (unit.compareTo(TimeUnit.SECONDS) < 0) { - // constants for conversion - final long C0 = 1L; - final long C1 = C0 * 1000L; - final long C2 = C1 * 1000L; - final long C3 = C2 * 1000L; - - long scale; - int width; - switch (unit) { - case MILLISECONDS : scale = C1; width = 3; break; - case MICROSECONDS : scale = C2; width = 6; break; - case NANOSECONDS : scale = C3; width = 9; break; - default: - throw new AssertionError("Unit not handled"); - } - long fraction = value % scale; + long fraction = asDaysAndNanos().fractionOfSecondInNanos(); if (fraction != 0L) { // fraction must be positive if (fraction < 0L) { - fraction += scale; + final long MAX_FRACTION_PLUS_1 = 1000L * 1000L * 1000L; + fraction += MAX_FRACTION_PLUS_1; if (ms != Long.MIN_VALUE) ms--; } @@ -266,7 +250,7 @@ public final class FileTime implements Comparable { // stripping any trailing zeros String s = Long.toString(fraction); int len = s.length(); - width -= len; + int width = 9 - len; StringBuilder sb = new StringBuilder("."); while (width-- > 0) { sb.append('0'); @@ -302,4 +286,76 @@ public final class FileTime implements Comparable { } return v; } + + /** + * Represents a FileTime's value as two longs: the number of days since + * the epoch, and the excess (in nanoseconds). This is used for comparing + * values with different units of granularity. + */ + private static class DaysAndNanos implements Comparable { + // constants for conversion + private static final long C0 = 1L; + private static final long C1 = C0 * 24L; + private static final long C2 = C1 * 60L; + private static final long C3 = C2 * 60L; + private static final long C4 = C3 * 1000L; + private static final long C5 = C4 * 1000L; + private static final long C6 = C5 * 1000L; + + /** + * The value (in days) since the epoch; can be negative. + */ + private final long days; + + /** + * The excess (in nanoseconds); can be negative if days <= 0. + */ + private final long excessNanos; + + /** + * Initializes a new instance of this class. + */ + DaysAndNanos(long value, TimeUnit unit) { + long scale; + switch (unit) { + case DAYS : scale = C0; break; + case HOURS : scale = C1; break; + case MINUTES : scale = C2; break; + case SECONDS : scale = C3; break; + case MILLISECONDS : scale = C4; break; + case MICROSECONDS : scale = C5; break; + case NANOSECONDS : scale = C6; break; + default : throw new AssertionError("Unit not handled"); + } + this.days = unit.toDays(value); + this.excessNanos = unit.toNanos(value - (this.days * scale)); + } + + /** + * Returns the fraction of a second, in nanoseconds. + */ + long fractionOfSecondInNanos() { + return excessNanos % (1000L * 1000L * 1000L); + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof DaysAndNanos) ? + compareTo((DaysAndNanos)obj) == 0 : false; + } + + @Override + public int hashCode() { + return (int)(days ^ (days >>> 32) ^ + excessNanos ^ (excessNanos >>> 32)); + } + + @Override + public int compareTo(DaysAndNanos other) { + if (this.days != other.days) + return (this.days < other.days) ? -1 : 1; + return (this.excessNanos < other.excessNanos) ? -1 : + (this.excessNanos == other.excessNanos) ? 0 : 1; + } + } } diff --git a/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java b/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java index 2ec2008d38285abdf63a47857b5a72ebf350770c..9f1a668a8c6d7a0a3fbc56bcacc97fd64add3527 100644 --- a/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java +++ b/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java @@ -60,8 +60,8 @@ import java.io.IOException; *

Usage Example: * Suppose we need to print out the owner and access permissions of a file: *

- *     FileRef file = ...
- *     PosixFileAttributes attrs = file.getFileAttributeView(PosixFileAttributeView.class)
+ *     Path file = ...
+ *     PosixFileAttributes attrs = Files.getFileAttributeView(file, PosixFileAttributeView.class)
  *         .readAttributes();
  *     System.out.format("%s %s%n",
  *         attrs.owner().getName(),
@@ -90,12 +90,12 @@ import java.io.IOException;
  * 
  * 
  *
- * 

The {@link FileRef#getAttribute getAttribute} method may be used to read + *

The {@link Files#getAttribute getAttribute} method may be used to read * any of these attributes, or any of the attributes defined by {@link * BasicFileAttributeView} as if by invoking the {@link #readAttributes * readAttributes()} method. * - *

The {@link FileRef#setAttribute setAttribute} method may be used to update + *

The {@link Files#setAttribute setAttribute} method may be used to update * the file's last modified time, last access time or create time attributes as * defined by {@link BasicFileAttributeView}. It may also be used to update * the permissions, owner, or group-owner as if by invoking the {@link @@ -105,8 +105,8 @@ import java.io.IOException; *

Setting Initial Permissions

*

Implementations supporting this attribute view may also support setting * the initial permissions when creating a file or directory. The - * initial permissions are provided to the {@link Path#createFile createFile} - * or {@link Path#createDirectory createDirectory} methods as a {@link + * initial permissions are provided to the {@link Files#createFile createFile} + * or {@link Files#createDirectory createDirectory} methods as a {@link * FileAttribute} with {@link FileAttribute#name name} {@code "posix:permissions"} * and a {@link FileAttribute#value value} that is the set of permissions. The * following example uses the {@link PosixFilePermissions#asFileAttribute @@ -117,7 +117,7 @@ import java.io.IOException; * Path path = ... * Set<PosixFilePermission> perms = * EnumSet.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ); - * path.createFile(PosixFilePermissions.asFileAttribute(perms)); + * Files.createFile(path, PosixFilePermissions.asFileAttribute(perms)); *

* *

When the access permissions are set at file creation time then the actual @@ -128,13 +128,11 @@ import java.io.IOException; * the access permissions, and the underlying file system supports access * permissions, then it is required that the value of the actual access * permissions will be equal or less than the value of the attribute - * provided to the {@link java.nio.file.Path#createFile createFile} or - * {@link java.nio.file.Path#createDirectory createDirectory} methods. In - * other words, the file may be more secure than requested. + * provided to the {@link Files#createFile createFile} or {@link + * Files#createDirectory createDirectory} methods. In other words, the file may + * be more secure than requested. * * @since 1.7 - * - * @see Attributes#readPosixFileAttributes */ public interface PosixFileAttributeView diff --git a/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java b/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java index 6dfd650c327a06144e6c5c1108e26c990c48abe7..361d4c2cc6ebdc46397731e8445fe9c0d88150e7 100644 --- a/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java +++ b/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java @@ -37,8 +37,6 @@ import java.util.Set; * PosixFileAttributeView#readAttributes readAttributes} method. * * @since 1.7 - * - * @see Attributes#readPosixFileAttributes */ public interface PosixFileAttributes diff --git a/src/share/classes/java/nio/file/attribute/PosixFilePermission.java b/src/share/classes/java/nio/file/attribute/PosixFilePermission.java index 3c5f33f86c77a86a450d308067b7c718225693ff..52419b7b0aa5edadabe9e4db47f5c81e6cfde032 100644 --- a/src/share/classes/java/nio/file/attribute/PosixFilePermission.java +++ b/src/share/classes/java/nio/file/attribute/PosixFilePermission.java @@ -25,14 +25,12 @@ package java.nio.file.attribute; -import java.util.*; - /** * Defines the bits for use with the {@link PosixFileAttributes#permissions() * permissions} attribute. * - *

The {@link PosixFileAttributes} class defines method methods for - * manipulating {@link Set sets} of permissions. + *

The {@link PosixFilePermissions} class defines methods for manipulating + * set of permissions. * * @since 1.7 */ diff --git a/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java b/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java index b3903957ef3f02dba1e08e45635e7d08b005c853..7499fa9498feed5a78c4a32d4e4a90fd4ecbb824 100644 --- a/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java +++ b/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java @@ -126,7 +126,7 @@ public final class PosixFilePermissions { public static Set fromString(String perms) { if (perms.length() != 9) throw new IllegalArgumentException("Invalid mode"); - Set result = new HashSet(); + Set result = EnumSet.noneOf(PosixFilePermission.class); if (isR(perms.charAt(0))) result.add(OWNER_READ); if (isW(perms.charAt(1))) result.add(OWNER_WRITE); if (isX(perms.charAt(2))) result.add(OWNER_EXECUTE); @@ -141,8 +141,8 @@ public final class PosixFilePermissions { /** * Creates a {@link FileAttribute}, encapsulating a copy of the given file - * permissions, suitable for passing to the {@link java.nio.file.Path#createFile - * createFile} or {@link java.nio.file.Path#createDirectory createDirectory} + * permissions, suitable for passing to the {@link java.nio.file.Files#createFile + * createFile} or {@link java.nio.file.Files#createDirectory createDirectory} * methods. * * @param perms diff --git a/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java b/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java index 04493e3936935db251c4ac45dc1edccfa93ce34b..41aaf2f107d565c30e60d0afe1966fd91990cd1e 100644 --- a/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java +++ b/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java @@ -59,9 +59,9 @@ import java.io.IOException; * attributes. * *

Where dynamic access to file attributes is required, the {@link - * java.nio.file.FileRef#getAttribute getAttribute} method may be used to read + * java.nio.file.Files#getAttribute getAttribute} method may be used to read * the attribute value. The attribute value is returned as a byte array (byte[]). - * The {@link java.nio.file.FileRef#setAttribute setAttribute} method may be used + * The {@link java.nio.file.Files#setAttribute setAttribute} method may be used * to write the value of a user-defined attribute from a buffer (as if by * invoking the {@link #write write} method), or byte array (byte[]). * @@ -132,8 +132,8 @@ public interface UserDefinedFileAttributeView * Suppose we want to read a file's MIME type that is stored as a user-defined * attribute with the name "{@code user.mimetype}". *

-     *    UserDefinedFileAttributeView view = file
-     *        .getFileAttributeView(UserDefinedFileAttributeView.class);
+     *    UserDefinedFileAttributeView view =
+     *        Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
      *    String name = "user.mimetype";
      *    ByteBuffer buf = ByteBuffer.allocate(view.size(name));
      *    view.read(name, buf);
@@ -189,8 +189,8 @@ public interface UserDefinedFileAttributeView
      * 

Usage Example: * Suppose we want to write a file's MIME type as a user-defined attribute: *

-     *    UserDefinedFileAttributeView view = file
-     *        .getFileAttributeView(UserDefinedFileAttributeView.class);
+     *    UserDefinedFileAttributeView view =
+     *        FIles.getFileAttributeView(path, UserDefinedFileAttributeView.class);
      *    view.write("user.mimetype", Charset.defaultCharset().encode("text/html"));
      * 
* diff --git a/src/share/classes/java/nio/file/attribute/package-info.java b/src/share/classes/java/nio/file/attribute/package-info.java index a82881176dfa5642ddf01df336f72c21596d19a2..0f06fded673496c4ed2534d33a65659d876b6063 100644 --- a/src/share/classes/java/nio/file/attribute/package-info.java +++ b/src/share/classes/java/nio/file/attribute/package-info.java @@ -46,8 +46,6 @@ * Can read or update user-defined file attributes *   {@link java.nio.file.attribute.FileStoreAttributeView} * Can read or update file system attributes - *     {@link java.nio.file.attribute.FileStoreSpaceAttributeView}   - * Can read file system space usage related attributes * * *

An attribute view provides a read-only or updatable view of the non-opaque @@ -55,7 +53,7 @@ * The {@link java.nio.file.attribute.FileAttributeView} interface is * extended by several other interfaces that that views to specific sets of file * attributes. {@code FileAttributeViews} are selected by invoking the {@link - * java.nio.file.FileRef#getFileAttributeView} method with a + * java.nio.file.Files#getFileAttributeView} method with a * type-token to identify the required view. Views can also be identified * by name. The {@link java.nio.file.attribute.FileStoreAttributeView} interface * provides access to file store attributes. A {@code FileStoreAttributeView} of @@ -83,13 +81,6 @@ * on the model defined by * RFC 3530: Network File System (NFS) version 4 Protocol. * - *

The {@link java.nio.file.attribute.FileStoreSpaceAttributeView} class - * defines methods to read file system space usage related attributes of a file system. - * - *

The {@link java.nio.file.attribute.Attributes} utility class defines - * static methods to access file or file system attribute using the above - * attribute views. - * *

In addition to attribute views, this package also defines classes and * interfaces that are used when accessing attributes: * diff --git a/src/share/classes/java/nio/file/package-info.java b/src/share/classes/java/nio/file/package-info.java index d5fa4d6bbd72dc9641457c181a856b11cd073151..5a687774aef28b90f2fe7f63bdf8e0002a7e9078 100644 --- a/src/share/classes/java/nio/file/package-info.java +++ b/src/share/classes/java/nio/file/package-info.java @@ -31,7 +31,7 @@ * systems. The API to access file and file system attributes is defined in the * {@link java.nio.file.attribute} package. The {@link java.nio.file.spi} * package is used by service provider implementors wishing to extend the - * platform default provider, or to construct other provider implementations. + * platform default provider, or to construct other provider implementations.

* *

Symbolic Links

* Many operating systems and file systems support for symbolic links. @@ -43,7 +43,7 @@ * target of the link. This package includes support for symbolic links where * implementations provide these semantics. File systems may support other types * that are semantically close but support for these other types of links is - * not included in this package. + * not included in this package.

* *

Interoperability

* The {@link java.io.File} class defines the {@link java.io.File#toPath @@ -52,7 +52,7 @@ * {@code Path} can be used to operate on the same file as the {@code File} * object. The {@code Path} specification provides further information * on the interoperability between {@code Path} - * and {@code java.io.File} objects. + * and {@code java.io.File} objects.

* *

Visibility

* The view of the files and file system provided by classes in this package are @@ -63,7 +63,7 @@ * network-filesystem protocols. This is true regardless of the language in which * these other programs are written, and whether they are running on the same machine * or on some other machine. The exact nature of any such inconsistencies are - * system-dependent and are therefore unspecified. + * system-dependent and are therefore unspecified.

* *

Synchronized I/O File Integrity

* The {@link java.nio.file.StandardOpenOption#SYNC SYNC} and {@link @@ -80,14 +80,14 @@ * crash. If the file does not reside on a local device then no such guarantee * is made. Whether this guarantee is possible with other {@link * java.nio.file.spi.FileSystemProvider provider} implementations is provider - * specific. + * specific.

* *

General Exceptions

* Unless otherwise noted, passing a {@code null} argument to a constructor * or method of any class or interface in this package will cause a {@link * java.lang.NullPointerException NullPointerException} to be thrown. Additionally, * invoking a method with a collection containing a {@code null} element will - * cause a {@code NullPointerException}, unless otherwise specified. + * cause a {@code NullPointerException}, unless otherwise specified.

* *

Unless otherwise noted, methods that attempt to access the file system * will throw {@link java.nio.file.ClosedFileSystemException} when invoked on @@ -95,12 +95,13 @@ * {@link java.nio.file.FileSystem#close closed}. Additionally, any methods * that attempt write access to a file system will throw {@link * java.nio.file.ReadOnlyFileSystemException} when invoked on an object associated - * with a {@link java.nio.file.FileSystem} that only provides read-only access. + * with a {@link java.nio.file.FileSystem} that only provides read-only + * access.

* *

Unless otherwise noted, invoking a method of any class or interface in * this package created by one {@link java.nio.file.spi.FileSystemProvider * provider} with a parameter that is an object created by another provider, - * will throw {@link java.nio.file.ProviderMismatchException}. + * will throw {@link java.nio.file.ProviderMismatchException}.

* *

Optional Specific Exceptions

* Most of the methods defined by classes in this package that access the diff --git a/src/share/classes/java/nio/file/spi/FileSystemProvider.java b/src/share/classes/java/nio/file/spi/FileSystemProvider.java index a267ad11bba844cbd67044a03b0a00d97b060316..ad285bd6ddb30dfb3414d626931a6413a9354e92 100644 --- a/src/share/classes/java/nio/file/spi/FileSystemProvider.java +++ b/src/share/classes/java/nio/file/spi/FileSystemProvider.java @@ -26,17 +26,21 @@ package java.nio.file.spi; import java.nio.file.*; -import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.*; import java.nio.channels.*; import java.net.URI; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; import java.util.*; import java.util.concurrent.ExecutorService; import java.security.AccessController; import java.security.PrivilegedAction; -import java.io.IOException; /** - * Service-provider class for file systems. + * Service-provider class for file systems. The methods defined by the {@link + * java.nio.file.Files} class will typically delegate to an instance of this + * class. * *

A file system provider is a concrete implementation of this class that * implements the abstract methods defined by this class. A provider is @@ -64,13 +68,6 @@ import java.io.IOException; * the {@code newFileSystem} method is invoked. In the case of the default * provider, the {@code FileSystem} is created when the provider is initialized. * - *

In addition to file systems, a provider is also a factory for {@link - * FileChannel} and {@link AsynchronousFileChannel} channels. The {@link - * #newFileChannel newFileChannel} and {@link #newAsynchronousFileChannel - * AsynchronousFileChannel} methods are defined to open or create files, returning - * a channel to access the file. These methods are invoked by static factory - * methods defined in the {@link java.nio.channels} package. - * *

All of the methods in this class are safe for use by multiple concurrent * threads. * @@ -202,9 +199,10 @@ public abstract class FileSystemProvider { * *

This method throws {@link FileSystemAlreadyExistsException} if the * file system already exists because it was previously created by an - * invocation of this method. Once a file system is {@link FileSystem#close - * closed} it is provider-dependent if the provider allows a new file system - * to be created with the same URI as a file system it previously created. + * invocation of this method. Once a file system is {@link + * java.nio.file.FileSystem#close closed} it is provider-dependent if the + * provider allows a new file system to be created with the same URI as a + * file system it previously created. * * @param uri * URI reference @@ -234,20 +232,21 @@ public abstract class FileSystemProvider { * *

This method returns a reference to a {@code FileSystem} that was * created by invoking the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)} - * method. File systems created the {@link #newFileSystem(FileRef,Map) - * newFileSystem(FileRef,Map)} method are not returned by this method. + * method. File systems created the {@link #newFileSystem(Path,Map) + * newFileSystem(Path,Map)} method are not returned by this method. * The file system is identified by its {@code URI}. Its exact form * is highly provider dependent. In the case of the default provider the URI's * path component is {@code "/"} and the authority, query and fragment components * are undefined (Undefined components are represented by {@code null}). * - *

Once a file system created by this provider is {@link FileSystem#close - * closed} it is provider-dependent if this method returns a reference to - * the closed file system or throws {@link FileSystemNotFoundException}. - * If the provider allows a new file system to be created with the same URI - * as a file system it previously created then this method throws the - * exception if invoked after the file system is closed (and before a new - * instance is created by the {@link #newFileSystem newFileSystem} method). + *

Once a file system created by this provider is {@link + * java.nio.file.FileSystem#close closed} it is provider-dependent if this + * method returns a reference to the closed file system or throws {@link + * FileSystemNotFoundException}. If the provider allows a new file system to + * be created with the same URI as a file system it previously created then + * this method throws the exception if invoked after the file system is + * closed (and before a new instance is created by the {@link #newFileSystem + * newFileSystem} method). * *

If a security manager is installed then a provider implementation * may require to check a permission before returning a reference to an @@ -306,17 +305,16 @@ public abstract class FileSystemProvider { * *

This method is intended for specialized providers of pseudo file * systems where the contents of one or more files is treated as a file - * system. The {@code file} parameter is a reference to an existing file - * and the {@code env} parameter is a map of provider specific properties to - * configure the file system. + * system. The {@code env} parameter is a map of provider specific properties + * to configure the file system. * *

If this provider does not support the creation of such file systems * or if the provider does not recognize the file type of the given file then * it throws {@code UnsupportedOperationException}. The default implementation * of this method throws {@code UnsupportedOperationException}. * - * @param file - * The file + * @param path + * The path to the file * @param env * A map of provider specific properties to configure the file system; * may be empty @@ -336,32 +334,121 @@ public abstract class FileSystemProvider { * If a security manager is installed and it denies an unspecified * permission. */ - public FileSystem newFileSystem(FileRef file, Map env) + public FileSystem newFileSystem(Path path, Map env) throws IOException { throw new UnsupportedOperationException(); } /** - * Opens or creates a file for reading and/or writing, returning a file - * channel to access the file. + * Opens a file, returning an input stream to read from the file. This + * method works in exactly the manner specified by the {@link + * Files#newInputStream} method. + * + *

The default implementation of this method opens a channel to the file + * as if by invoking the {@link #newByteChannel} method and constructs a + * stream that reads bytes from the channel. This method should be overridden + * where appropriate. + * + * @param path + * the path to the file to open + * @param options + * options specifying how the file is opened + * + * @return a new input stream + * + * @throws IllegalArgumentException + * if an invalid combination of options is specified + * @throws UnsupportedOperationException + * if an unsupported option is specified + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + public InputStream newInputStream(Path path, OpenOption... options) + throws IOException + { + if (options.length > 0) { + for (OpenOption opt: options) { + if (opt != StandardOpenOption.READ) + throw new UnsupportedOperationException("'" + opt + "' not allowed"); + } + } + return Channels.newInputStream(Files.newByteChannel(path)); + } + + /** + * Opens or creates a file, returning an output stream that may be used to + * write bytes to the file. This method works in exactly the manner + * specified by the {@link Files#newOutputStream} method. * - *

This method is invoked by the {@link FileChannel#open(Path,Set,FileAttribute[]) - * FileChannel.open} method to open a file channel. A provider that does not - * support all the features required to construct a file channel throws - * {@code UnsupportedOperationException}. The default provider is required - * to support the creation of file channels. When not overridden, the - * default implementation throws {@code UnsupportedOperationException}. + *

The default implementation of this method opens a channel to the file + * as if by invoking the {@link #newByteChannel} method and constructs a + * stream that writes bytes to the channel. This method should be overridden + * where appropriate. + * + * @param path + * the path to the file to open or create + * @param options + * options specifying how the file is opened + * + * @return a new output stream + * + * @throws IllegalArgumentException + * if {@code options} contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported option is specified + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the file. The {@link + * SecurityManager#checkDelete(String) checkDelete} method is + * invoked to check delete access if the file is opened with the + * {@code DELETE_ON_CLOSE} option. + */ + public OutputStream newOutputStream(Path path, OpenOption... options) + throws IOException + { + int len = options.length; + Set opts = new HashSet(len + 3); + if (len == 0) { + opts.add(StandardOpenOption.CREATE); + opts.add(StandardOpenOption.TRUNCATE_EXISTING); + } else { + for (OpenOption opt: options) { + if (opt == StandardOpenOption.READ) + throw new IllegalArgumentException("READ not allowed"); + opts.add(opt); + } + } + opts.add(StandardOpenOption.WRITE); + return Channels.newOutputStream(newByteChannel(path, opts)); + } + + /** + * Opens or creates a file for reading and/or writing, returning a file + * channel to access the file. This method works in exactly the manner + * specified by the {@link FileChannel#open(Path,Set,FileAttribute[]) + * FileChannel.open} method. A provider that does not support all the + * features required to construct a file channel throws {@code + * UnsupportedOperationException}. The default provider is required to + * support the creation of file channels. When not overridden, the default + * implementation throws {@code UnsupportedOperationException}. * * @param path - * The path of the file to open or create + * the path of the file to open or create * @param options - * Options specifying how the file is opened + * options specifying how the file is opened * @param attrs - * An optional list of file attributes to set atomically when + * an optional list of file attributes to set atomically when * creating the file * - * @return A new file channel + * @return a new file channel * * @throws IllegalArgumentException * If the set contains an invalid combination of options @@ -387,11 +474,10 @@ public abstract class FileSystemProvider { /** * Opens or creates a file for reading and/or writing, returning an - * asynchronous file channel to access the file. - * - *

This method is invoked by the {@link + * asynchronous file channel to access the file. This method works in + * exactly the manner specified by the {@link * AsynchronousFileChannel#open(Path,Set,ExecutorService,FileAttribute[]) - * AsynchronousFileChannel.open} method to open an asynchronous file channel. + * AsynchronousFileChannel.open} method. * A provider that does not support all the features required to construct * an asynchronous file channel throws {@code UnsupportedOperationException}. * The default provider is required to support the creation of asynchronous @@ -399,17 +485,17 @@ public abstract class FileSystemProvider { * method throws {@code UnsupportedOperationException}. * * @param path - * The path of the file to open or create + * the path of the file to open or create * @param options - * Options specifying how the file is opened + * options specifying how the file is opened * @param executor - * The thread pool or {@code null} to associate the channel with + * the thread pool or {@code null} to associate the channel with * the default thread pool * @param attrs - * An optional list of file attributes to set atomically when + * an optional list of file attributes to set atomically when * creating the file * - * @return A new asynchronous file channel + * @return a new asynchronous file channel * * @throws IllegalArgumentException * If the set contains an invalid combination of options @@ -434,4 +520,569 @@ public abstract class FileSystemProvider { { throw new UnsupportedOperationException(); } + + /** + * Opens or creates a file, returning a seekable byte channel to access the + * file. This method works in exactly the manner specified by the {@link + * Files#newByteChannel(Path,Set,FileAttribute[])} method. + * + * @param path + * the path to the file to open or create + * @param options + * options specifying how the file is opened + * @param attrs + * an optional list of file attributes to set atomically when + * creating the file + * + * @return a new seekable byte channel + * + * @throws IllegalArgumentException + * if the set contains an invalid combination of options + * @throws UnsupportedOperationException + * if an unsupported open option is specified or the array contains + * attributes that cannot be set atomically when creating the file + * @throws FileAlreadyExistsException + * if a file of that name already exists and the {@link + * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified + * (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the path if the file is + * opened for reading. The {@link SecurityManager#checkWrite(String) + * checkWrite} method is invoked to check write access to the path + * if the file is opened for writing. The {@link + * SecurityManager#checkDelete(String) checkDelete} method is + * invoked to check delete access if the file is opened with the + * {@code DELETE_ON_CLOSE} option. + */ + public abstract SeekableByteChannel newByteChannel(Path path, + Set options, FileAttribute... attrs) throws IOException; + + /** + * Opens a directory, returning a {@code DirectoryStream} to iterate over + * the entries in the directory. This method works in exactly the manner + * specified by the {@link + * Files#newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter)} + * method. + * + * @param dir + * the path to the directory + * @param filter + * the directory stream filter + * + * @return a new and open {@code DirectoryStream} object + * + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + */ + public abstract DirectoryStream newDirectoryStream(Path dir, + DirectoryStream.Filter filter) throws IOException; + + /** + * Creates a new directory. This method works in exactly the manner + * specified by the {@link Files#createDirectory} method. + * + * @param dir + * the directory to create + * @param attrs + * an optional list of file attributes to set atomically when + * creating the directory + * + * @throws UnsupportedOperationException + * if the array contains an attribute that cannot be set atomically + * when creating the directory + * @throws FileAlreadyExistsException + * if a directory could not otherwise be created because a file of + * that name already exists (optional specific exception) + * @throws IOException + * if an I/O error occurs or the parent directory does not exist + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to the new directory. + */ + public abstract void createDirectory(Path dir, FileAttribute... attrs) + throws IOException; + + /** + * Creates a symbolic link to a target. This method works in exactly the + * manner specified by the {@link Files#createSymbolicLink} method. + * + *

The default implementation of this method throws {@code + * UnsupportedOperationException}. + * + * @param link + * the path of the symbolic link to create + * @param target + * the target of the symbolic link + * @param attrs + * the array of attributes to set atomically when creating the + * symbolic link + * + * @throws UnsupportedOperationException + * if the implementation does not support symbolic links or the + * array contains an attribute that cannot be set atomically when + * creating the symbolic link + * @throws FileAlreadyExistsException + * if a file with the name already exists (optional specific + * exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager + * is installed, it denies {@link LinkPermission}("symbolic") + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the path of the symbolic link. + */ + public void createSymbolicLink(Path link, Path target, FileAttribute... attrs) + throws IOException + { + throw new UnsupportedOperationException(); + } + + /** + * Creates a new link (directory entry) for an existing file. This method + * works in exactly the manner specified by the {@link Files#createLink} + * method. + * + *

The default implementation of this method throws {@code + * UnsupportedOperationException}. + * + * @param link + * the link (directory entry) to create + * @param existing + * a path to an existing file + * + * @throws UnsupportedOperationException + * if the implementation does not support adding an existing file + * to a directory + * @throws FileAlreadyExistsException + * if the entry could not otherwise be created because a file of + * that name already exists (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager + * is installed, it denies {@link LinkPermission}("hard") + * or its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to either the link or the + * existing file. + */ + public void createLink(Path link, Path existing) throws IOException { + throw new UnsupportedOperationException(); + } + + /** + * Deletes a file. This method works in exactly the manner specified by the + * {@link Files#delete} method. + * + * @param path + * the path to the file to delete + * + * @throws NoSuchFileException + * if the file does not exist (optional specific exception) + * @throws DirectoryNotEmptyException + * if the file is a directory and could not otherwise be deleted + * because the directory is not empty (optional specific + * exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkDelete(String)} method + * is invoked to check delete access to the file + */ + public abstract void delete(Path path) throws IOException; + + /** + * Deletes a file if it exists. This method works in exactly the manner + * specified by the {@link Files#deleteIfExists} method. + * + *

The default implementation of this method simply invokes {@link + * #delete} ignoring the {@code NoSuchFileException} when the file does not + * exist. It may be overridden where appropriate. + * + * @param path + * the path to the file to delete + * + * @return {@code true} if the file was deleted by this method; {@code + * false} if the file could not be deleted because it did not + * exist + * + * @throws DirectoryNotEmptyException + * if the file is a directory and could not otherwise be deleted + * because the directory is not empty (optional specific + * exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkDelete(String)} method + * is invoked to check delete access to the file + */ + public boolean deleteIfExists(Path path) throws IOException { + try { + delete(path); + return true; + } catch (NoSuchFileException ignore) { + return false; + } + } + + /** + * Reads the target of a symbolic link. This method works in exactly the + * manner specified by the {@link Files#readSymbolicLink} method. + * + *

The default implementation of this method throws {@code + * UnsupportedOperationException}. + * + * @param link + * the path to the symbolic link + * + * @throws UnsupportedOperationException + * if the implementation does not support symbolic links + * @throws NotLinkException + * if the target could otherwise not be read because the file + * is not a symbolic link (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager + * is installed, it checks that {@code FilePermission} has been + * granted with the "{@code readlink}" action to read the link. + */ + public Path readSymbolicLink(Path link) throws IOException { + throw new UnsupportedOperationException(); + } + + /** + * Copy a file to a target file. This method works in exactly the manner + * specified by the {@link Files#copy(Path,Path,CopyOption[])} method + * except that both the source and target paths must be associated with + * this provider. + * + * @param source + * the path to the file to copy + * @param target + * the path to the target file + * @param options + * options specifying how the copy should be done + * + * @throws UnsupportedOperationException + * if the array contains a copy option that is not supported + * @throws FileAlreadyExistsException + * if the target file exists but cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified (optional + * specific exception) + * @throws DirectoryNotEmptyException + * the {@code REPLACE_EXISTING} option is specified but the file + * cannot be replaced because it is a non-empty directory + * (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the source file, the + * {@link SecurityManager#checkWrite(String) checkWrite} is invoked + * to check write access to the target file. If a symbolic link is + * copied the security manager is invoked to check {@link + * LinkPermission}{@code ("symbolic")}. + */ + public abstract void copy(Path source, Path target, CopyOption... options) + throws IOException; + + /** + * Move or rename a file to a target file. This method works in exactly the + * manner specified by the {@link Files#move} method except that both the + * source and target paths must be associated with this provider. + * + * @param source + * the path to the file to move + * @param target + * the path to the target file + * @param options + * options specifying how the move should be done + * + * @throws UnsupportedOperationException + * if the array contains a copy option that is not supported + * @throws FileAlreadyExistsException + * if the target file exists but cannot be replaced because the + * {@code REPLACE_EXISTING} option is not specified (optional + * specific exception) + * @throws DirectoryNotEmptyException + * the {@code REPLACE_EXISTING} option is specified but the file + * cannot be replaced because it is a non-empty directory + * (optional specific exception) + * @throws AtomicMoveNotSupportedException + * if the options array contains the {@code ATOMIC_MOVE} option but + * the file cannot be moved as an atomic file system operation. + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkWrite(String) checkWrite} + * method is invoked to check write access to both the source and + * target file. + */ + public abstract void move(Path source, Path target, CopyOption... options) + throws IOException; + + /** + * Tests if two paths locate the same file. This method works in exactly the + * manner specified by the {@link Files#isSameFile} method. + * + * @param path + * one path to the file + * @param path2 + * the other path + * + * @return {@code true} if, and only if, the two paths locate the same file + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to both files. + */ + public abstract boolean isSameFile(Path path, Path path2) + throws IOException; + + /** + * Tells whether or not a file is considered hidden. This method + * works in exactly the manner specified by the {@link Files#isHidden} + * method. + * + *

This method is invoked by the {@link Files#isHidden isHidden} method. + * + * @param path + * the path to the file to test + * + * @return {@code true} if the file is considered hidden + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + */ + public abstract boolean isHidden(Path path) throws IOException; + + /** + * Returns the {@link FileStore} representing the file store where a file + * is located. This method works in exactly the manner specified by the + * {@link Files#getFileStore} method. + * + * @param path + * the path to the file + * + * @return the file store where the file is stored + * + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file, and in + * addition it checks {@link RuntimePermission} + * ("getFileStoreAttributes") + */ + public abstract FileStore getFileStore(Path path) throws IOException; + + /** + * Checks the existence, and optionally the accessibility, of a file. + * + *

This method may be used by the {@link Files#isReadable isReadable}, + * {@link Files#isWritable isWritable} and {@link Files#isExecutable + * isExecutable} methods to check the accessibility of a file. + * + *

This method checks the existence of a file and that this Java virtual + * machine has appropriate privileges that would allow it access the file + * according to all of access modes specified in the {@code modes} parameter + * as follows: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Value Description
{@link AccessMode#READ READ} Checks that the file exists and that the Java virtual machine has + * permission to read the file.
{@link AccessMode#WRITE WRITE} Checks that the file exists and that the Java virtual machine has + * permission to write to the file,
{@link AccessMode#EXECUTE EXECUTE} Checks that the file exists and that the Java virtual machine has + * permission to {@link Runtime#exec execute} the file. The semantics + * may differ when checking access to a directory. For example, on UNIX + * systems, checking for {@code EXECUTE} access checks that the Java + * virtual machine has permission to search the directory in order to + * access file or subdirectories.
+ * + *

If the {@code modes} parameter is of length zero, then the existence + * of the file is checked. + * + *

This method follows symbolic links if the file referenced by this + * object is a symbolic link. Depending on the implementation, this method + * may require to read file permissions, access control lists, or other + * file attributes in order to check the effective access to the file. To + * determine the effective access to a file may require access to several + * attributes and so in some implementations this method may not be atomic + * with respect to other file system operations. + * + * @param path + * the path to the file to check + * @param modes + * The access modes to check; may have zero elements + * + * @throws UnsupportedOperationException + * an implementation is required to support checking for + * {@code READ}, {@code WRITE}, and {@code EXECUTE} access. This + * exception is specified to allow for the {@code Access} enum to + * be extended in future releases. + * @throws NoSuchFileException + * if a file does not exist (optional specific exception) + * @throws AccessDeniedException + * the requested access would be denied or the access cannot be + * determined because the Java virtual machine has insufficient + * privileges or other reasons. (optional specific exception) + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * is invoked when checking read access to the file or only the + * existence of the file, the {@link SecurityManager#checkWrite(String) + * checkWrite} is invoked when checking write access to the file, + * and {@link SecurityManager#checkExec(String) checkExec} is invoked + * when checking execute access. + */ + public abstract void checkAccess(Path path, AccessMode... modes) + throws IOException; + + /** + * Returns a file attribute view of a given type. This method works in + * exactly the manner specified by the {@link Files#getFileAttributeView} + * method. + * + * @param path + * the path to the file + * @param type + * the {@code Class} object corresponding to the file attribute view + * @param options + * options indicating how symbolic links are handled + * + * @return a file attribute view of the specified type, or {@code null} if + * the attribute view type is not available + */ + public abstract V + getFileAttributeView(Path path, Class type, LinkOption... options); + + /** + * Reads a file's attributes as a bulk operation. This method works in + * exactly the manner specified by the {@link + * Files#readAttributes(Path,Class,LinkOption[])} method. + * + * @param path + * the path to the file + * @param type + * the {@code Class} of the file attributes required + * to read + * @param options + * options indicating how symbolic links are handled + * + * @return the file attributes + * + * @throws UnsupportedOperationException + * if an attributes of the given type are not supported + * @throws IOException + * if an I/O error occurs + * @throws SecurityException + * In the case of the default provider, a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file + */ + public abstract A + readAttributes(Path path, Class type, LinkOption... options) throws IOException; + + /** + * Reads a set of file attributes as a bulk operation. This method works in + * exactly the manner specified by the {@link + * Files#readAttributes(Path,String,LinkOption[])} method. + * + * @param path + * the path to the file + * @param attributes + * the attributes to read + * @param options + * options indicating how symbolic links are handled + * + * @return a map of the attributes returned; may be empty. The map's keys + * are the attribute names, its values are the attribute values + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkRead(String) checkRead} + * method denies read access to the file. If this method is invoked + * to read security sensitive attributes then the security manager + * may be invoke to check for additional permissions. + */ + public abstract Map readAttributes(Path path, String attributes, + LinkOption... options) + throws IOException; + + /** + * Sets the value of a file attribute. This method works in exactly the + * manner specified by the {@link Files#setAttribute} method. + * + * @param path + * the path to the file + * @param attribute + * the attribute to set + * @param value + * the attribute value + * @param options + * options indicating how symbolic links are handled + * + * @throws UnsupportedOperationException + * if the attribute view is not available or it does not support + * updating the attribute + * @throws IllegalArgumentException + * if the attribute value is of the correct type but has an + * inappropriate value + * @throws ClassCastException + * If the attribute value is not of the expected type or is a + * collection containing elements that are not of the expected + * type + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, its {@link SecurityManager#checkWrite(String) checkWrite} + * method denies write access to the file. If this method is invoked + * to set security sensitive attributes then the security manager + * may be invoked to check for additional permissions. + */ + public abstract void setAttribute(Path path, String attribute, + Object value, LinkOption... options) + throws IOException; } diff --git a/src/share/classes/java/nio/file/spi/FileTypeDetector.java b/src/share/classes/java/nio/file/spi/FileTypeDetector.java index 21c130188fb5919678cc08293c5b9a5847e488f9..fd062804d6a4ab320dca9e1d4a695b998d5d27d4 100644 --- a/src/share/classes/java/nio/file/spi/FileTypeDetector.java +++ b/src/share/classes/java/nio/file/spi/FileTypeDetector.java @@ -25,7 +25,7 @@ package java.nio.file.spi; -import java.nio.file.FileRef; +import java.nio.file.Path; import java.io.IOException; /** @@ -42,7 +42,7 @@ import java.io.IOException; * href="../attribute/package-summary.html"> attribute or the bytes in a * file may be examined to guess its file type. * - * @see java.nio.file.Files#probeContentType(FileRef) + * @see java.nio.file.Files#probeContentType(Path) * * @since 1.7 */ @@ -83,8 +83,8 @@ public abstract class FileTypeDetector { * Message Bodies. The string must be parsable according to the * grammar in the RFC 2045. * - * @param file - * The file to probe + * @param path + * the path to the file to probe * * @return The content type or {@code null} if the file type is not * recognized @@ -101,6 +101,6 @@ public abstract class FileTypeDetector { * * @see java.nio.file.Files#probeContentType */ - public abstract String probeContentType(FileRef file) + public abstract String probeContentType(Path path) throws IOException; } diff --git a/src/share/classes/java/util/Scanner.java b/src/share/classes/java/util/Scanner.java index 834af330ff19a90b1c4f8497380b7efce6e8c637..4aa5c9fb8c58c35d7498ec446be6bc805bbb9b2d 100644 --- a/src/share/classes/java/util/Scanner.java +++ b/src/share/classes/java/util/Scanner.java @@ -25,7 +25,8 @@ package java.util; -import java.nio.file.FileRef; +import java.nio.file.Path; +import java.nio.file.Files; import java.util.regex.*; import java.io.*; import java.math.*; @@ -699,16 +700,16 @@ public final class Scanner implements Iterator, Closeable { * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}. * * @param source - * A file to be scanned + * the path to the file to be scanned * @throws IOException * if an I/O error occurs opening source * * @since 1.7 */ - public Scanner(FileRef source) + public Scanner(Path source) throws IOException { - this(source.newInputStream()); + this(Files.newInputStream(source)); } /** @@ -717,7 +718,7 @@ public final class Scanner implements Iterator, Closeable { * characters using the specified charset. * * @param source - * A file to be scanned + * the path to the file to be scanned * @param charsetName * The encoding type used to convert bytes from the file * into characters to be scanned @@ -727,12 +728,12 @@ public final class Scanner implements Iterator, Closeable { * if the specified encoding is not found * @since 1.7 */ - public Scanner(FileRef source, String charsetName) throws IOException { + public Scanner(Path source, String charsetName) throws IOException { this(Objects.nonNull(source), toCharset(charsetName)); } - private Scanner(FileRef source, Charset charset) throws IOException { - this(makeReadable(source.newInputStream(), charset)); + private Scanner(Path source, Charset charset) throws IOException { + this(makeReadable(Files.newInputStream(source), charset)); } /** diff --git a/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java b/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java index 65b965bb32bbd220a4f1a98c477a0fa54fb55a72..cd1e6c26b8d2d999e32d783d1c16a88f3c7fccc3 100644 --- a/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java +++ b/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java @@ -44,15 +44,6 @@ abstract class AbstractAclFileAttributeView return "acl"; } - @Override - public final Object getAttribute(String attribute) throws IOException { - if (attribute.equals(OWNER_NAME)) - return getOwner(); - if (attribute.equals(ACL_NAME)) - return getAcl(); - return null; - } - @Override @SuppressWarnings("unchecked") public final void setAttribute(String attribute, Object value) @@ -71,7 +62,7 @@ abstract class AbstractAclFileAttributeView } @Override - public final Map readAttributes(String[] attributes) + public final Map readAttributes(String[] attributes) throws IOException { boolean acl = false; @@ -91,7 +82,7 @@ abstract class AbstractAclFileAttributeView continue; } } - Map result = new HashMap(2); + Map result = new HashMap<>(2); if (acl) result.put(ACL_NAME, getAcl()); if (owner) diff --git a/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java b/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java index de84499cb780b0cf1aa7787281ebc958a6501f8c..6383c08edf1a64de8ec63c09b54bf5b669e87a46 100644 --- a/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java +++ b/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java @@ -53,30 +53,6 @@ abstract class AbstractBasicFileAttributeView return "basic"; } - @Override - public Object getAttribute(String attribute) throws IOException { - BasicFileAttributes attrs = readAttributes(); - if (attribute.equals(SIZE_NAME)) - return attrs.size(); - if (attribute.equals(CREATION_TIME_NAME)) - return attrs.creationTime(); - if (attribute.equals(LAST_ACCESS_TIME_NAME)) - return attrs.lastAccessTime(); - if (attribute.equals(LAST_MODIFIED_TIME_NAME)) - return attrs.lastModifiedTime(); - if (attribute.equals(FILE_KEY_NAME)) - return attrs.fileKey(); - if (attribute.equals(IS_DIRECTORY_NAME)) - return attrs.isDirectory(); - if (attribute.equals(IS_REGULAR_FILE_NAME)) - return attrs.isRegularFile(); - if (attribute.equals(IS_SYMBOLIC_LINK_NAME)) - return attrs.isSymbolicLink(); - if (attribute.equals(IS_OTHER_NAME)) - return attrs.isOther(); - return null; - } - @Override public void setAttribute(String attribute, Object value) throws IOException @@ -101,8 +77,8 @@ abstract class AbstractBasicFileAttributeView * Used to build a map of attribute name/values. */ static class AttributesBuilder { - private Set set = new HashSet(); - private Map map = new HashMap(); + private Set set = new HashSet<>(); + private Map map = new HashMap<>(); private boolean copyAll; private AttributesBuilder(String[] attributes) { @@ -172,7 +148,7 @@ abstract class AbstractBasicFileAttributeView } @Override - public Map readAttributes(String[] attributes) throws IOException { + public Map readAttributes(String[] attributes) throws IOException { AttributesBuilder builder = AttributesBuilder.create(attributes); addBasicAttributesToBuilder(readAttributes(), builder); return builder.unmodifiableMap(); diff --git a/src/share/classes/sun/nio/fs/AbstractFileSystemProvider.java b/src/share/classes/sun/nio/fs/AbstractFileSystemProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..95d1cb30931de80e6c470110b9b565d7a6a01edb --- /dev/null +++ b/src/share/classes/sun/nio/fs/AbstractFileSystemProvider.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.spi.FileSystemProvider; +import java.io.IOException; +import java.util.Map; +import java.util.Collections; + +/** + * Base implementation class of FileSystemProvider + */ + +abstract class AbstractFileSystemProvider extends FileSystemProvider { + protected AbstractFileSystemProvider() { } + + /** + * Splits the given attribute name into the name of an attribute view and + * the attribute. If the attribute view is not identified then it assumed + * to be "basic". + */ + private static String[] split(String attribute) { + String[] s = new String[2]; + int pos = attribute.indexOf(':'); + if (pos == -1) { + s[0] = "basic"; + s[1] = attribute; + } else { + s[0] = attribute.substring(0, pos++); + s[1] = (pos == attribute.length()) ? "" : attribute.substring(pos); + } + return s; + } + + /** + * Gets a DynamicFileAttributeView by name. Returns {@code null} if the + * view is not available. + */ + abstract DynamicFileAttributeView getFileAttributeView(Path file, + String name, + LinkOption... options); + + @Override + public final void setAttribute(Path file, + String attribute, + Object value, + LinkOption... options) + throws IOException + { + String[] s = split(attribute); + DynamicFileAttributeView view = getFileAttributeView(file, s[0], options); + if (view == null) + throw new UnsupportedOperationException("View '" + s[0] + "' not available"); + view.setAttribute(s[1], value); + } + + @Override + public final Map readAttributes(Path file, String attributes, LinkOption... options) + throws IOException + { + String[] s = split(attributes); + DynamicFileAttributeView view = getFileAttributeView(file, s[0], options); + if (view == null) + return Collections.emptyMap(); + return view.readAttributes(s[1].split(",")); + } + + /** + * Deletes a file. The {@code failIfNotExists} parameters determines if an + * {@code IOException} is thrown when the file does not exist. + */ + abstract boolean implDelete(Path file, boolean failIfNotExists) throws IOException; + + @Override + public final void delete(Path file) throws IOException { + implDelete(file, true); + } + + @Override + public final boolean deleteIfExists(Path file) throws IOException { + return implDelete(file, false); + } +} diff --git a/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java b/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java index 612e8e36f59ed0ba64749c66ab1f8331dcdd0229..2ab2961561c7df1d3e988d90f67d8b48ebdc5fcc 100644 --- a/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java +++ b/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java @@ -25,7 +25,7 @@ package sun.nio.fs; -import java.nio.file.FileRef; +import java.nio.file.Path; import java.nio.file.spi.FileTypeDetector; import java.util.Locale; import java.io.IOException; @@ -46,7 +46,7 @@ public abstract class AbstractFileTypeDetector * and checks that the content type's syntax is valid. */ @Override - public final String probeContentType(FileRef file) throws IOException { + public final String probeContentType(Path file) throws IOException { if (file == null) throw new NullPointerException("'file' is null"); String result = implProbeContentType(file); @@ -56,7 +56,7 @@ public abstract class AbstractFileTypeDetector /** * Probes the given file to guess its content type. */ - protected abstract String implProbeContentType(FileRef file) + protected abstract String implProbeContentType(Path file) throws IOException; /** diff --git a/src/share/classes/sun/nio/fs/AbstractPath.java b/src/share/classes/sun/nio/fs/AbstractPath.java index 17262b68c0420ad98b4626c093cb3afbe009765d..eae2ac964837b230ccc8d3f8f8705fc90e06de4a 100644 --- a/src/share/classes/sun/nio/fs/AbstractPath.java +++ b/src/share/classes/sun/nio/fs/AbstractPath.java @@ -26,391 +26,81 @@ package sun.nio.fs; import java.nio.file.*; -import static java.nio.file.StandardOpenOption.*; -import java.nio.file.attribute.*; -import java.nio.channels.*; -import java.nio.ByteBuffer; -import java.io.*; -import java.util.*; +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.NoSuchElementException; /** - * Base implementation class for a {@code Path}. + * Base implementation class of {@code Path}. */ -abstract class AbstractPath extends Path { +abstract class AbstractPath implements Path { protected AbstractPath() { } @Override - public final Path createFile(FileAttribute... attrs) - throws IOException - { - EnumSet options = EnumSet.of(CREATE_NEW, WRITE); - SeekableByteChannel sbc = newByteChannel(options, attrs); - try { - sbc.close(); - } catch (IOException x) { - // ignore - } - return this; + public final boolean startsWith(String other) { + return startsWith(getFileSystem().getPath(other)); } - /** - * Deletes a file. The {@code failIfNotExists} parameters determines if an - * {@code IOException} is thrown when the file does not exist. - */ - abstract void implDelete(boolean failIfNotExists) throws IOException; - @Override - public final void delete() throws IOException { - implDelete(true); + public final boolean endsWith(String other) { + return endsWith(getFileSystem().getPath(other)); } @Override - public final void deleteIfExists() throws IOException { - implDelete(false); + public final Path resolve(String other) { + return resolve(getFileSystem().getPath(other)); } @Override - public final InputStream newInputStream(OpenOption... options) - throws IOException - { - if (options.length > 0) { - for (OpenOption opt: options) { - if (opt != READ) - throw new UnsupportedOperationException("'" + opt + "' not allowed"); - } - } - return Channels.newInputStream(newByteChannel()); + public final Path resolveSibling(Path other) { + if (other == null) + throw new NullPointerException(); + Path parent = getParent(); + return (parent == null) ? other : parent.resolve(other); } @Override - public final OutputStream newOutputStream(OpenOption... options) - throws IOException - { - int len = options.length; - Set opts = new HashSet(len + 3); - if (len == 0) { - opts.add(CREATE); - opts.add(TRUNCATE_EXISTING); - } else { - for (OpenOption opt: options) { - if (opt == READ) - throw new IllegalArgumentException("READ not allowed"); - opts.add(opt); - } - } - opts.add(WRITE); - return Channels.newOutputStream(newByteChannel(opts)); + public final Path resolveSibling(String other) { + return resolveSibling(getFileSystem().getPath(other)); } @Override - public final SeekableByteChannel newByteChannel(OpenOption... options) - throws IOException - { - Set set = new HashSet(options.length); - Collections.addAll(set, options); - return newByteChannel(set); - } - - private static final DirectoryStream.Filter acceptAllFilter = - new DirectoryStream.Filter() { - @Override public boolean accept(Path entry) { return true; } - }; - - @Override - public final DirectoryStream newDirectoryStream() throws IOException { - return newDirectoryStream(acceptAllFilter); - } - - @Override - public final DirectoryStream newDirectoryStream(String glob) - throws IOException - { - // avoid creating a matcher if all entries are required. - if (glob.equals("*")) - return newDirectoryStream(); - - // create a matcher and return a filter that uses it. - final PathMatcher matcher = getFileSystem().getPathMatcher("glob:" + glob); - DirectoryStream.Filter filter = new DirectoryStream.Filter() { + public final Iterator iterator() { + return new Iterator() { + private int i = 0; @Override - public boolean accept(Path entry) { - return matcher.matches(entry.getName()); - } - }; - return newDirectoryStream(filter); - } - - @Override - public final boolean exists() { - try { - checkAccess(); - return true; - } catch (IOException x) { - // unable to determine if file exists - } - return false; - } - - @Override - public final boolean notExists() { - try { - checkAccess(); - return false; - } catch (NoSuchFileException x) { - // file confirmed not to exist - return true; - } catch (IOException x) { - return false; - } - } - - private static final WatchEvent.Modifier[] NO_MODIFIERS = new WatchEvent.Modifier[0]; - - @Override - public final WatchKey register(WatchService watcher, - WatchEvent.Kind... events) - throws IOException - { - return register(watcher, events, NO_MODIFIERS); - } - - abstract void implCopyTo(Path target, CopyOption... options) - throws IOException; - - @Override - public final Path copyTo(Path target, CopyOption... options) - throws IOException - { - if ((getFileSystem().provider() == target.getFileSystem().provider())) { - implCopyTo(target, options); - } else { - copyToForeignTarget(target, options); - } - return target; - } - - abstract void implMoveTo(Path target, CopyOption... options) - throws IOException; - - @Override - public final Path moveTo(Path target, CopyOption... options) - throws IOException - { - if ((getFileSystem().provider() == target.getFileSystem().provider())) { - implMoveTo(target, options); - } else { - // different providers so copy + delete - copyToForeignTarget(target, convertMoveToCopyOptions(options)); - delete(); - } - return target; - } - - /** - * Converts the given array of options for moving a file to options suitable - * for copying the file when a move is implemented as copy + delete. - */ - private static CopyOption[] convertMoveToCopyOptions(CopyOption... options) - throws AtomicMoveNotSupportedException - { - int len = options.length; - CopyOption[] newOptions = new CopyOption[len+2]; - for (int i=0; i 0; - buf.flip(); - while (buf.hasRemaining()) { - sbc.write(buf); - } - buf.rewind(); - } - - } finally { - sbc.close(); + @Override + public void remove() { + throw new UnsupportedOperationException(); } - } finally { - rbc.close(); - } - } - - /** - * Splits the given attribute name into the name of an attribute view and - * the attribute. If the attribute view is not identified then it assumed - * to be "basic". - */ - private static String[] split(String attribute) { - String[] s = new String[2]; - int pos = attribute.indexOf(':'); - if (pos == -1) { - s[0] = "basic"; - s[1] = attribute; - } else { - s[0] = attribute.substring(0, pos++); - s[1] = (pos == attribute.length()) ? "" : attribute.substring(pos); - } - return s; - } - - /** - * Gets a DynamicFileAttributeView by name. Returns {@code null} if the - * view is not available. - */ - abstract DynamicFileAttributeView getFileAttributeView(String name, - LinkOption... options); - - @Override - public final void setAttribute(String attribute, - Object value, - LinkOption... options) - throws IOException - { - String[] s = split(attribute); - DynamicFileAttributeView view = getFileAttributeView(s[0], options); - if (view == null) - throw new UnsupportedOperationException("View '" + s[0] + "' not available"); - view.setAttribute(s[1], value); + }; } @Override - public final Object getAttribute(String attribute, LinkOption... options) - throws IOException - { - String[] s = split(attribute); - DynamicFileAttributeView view = getFileAttributeView(s[0], options); - return (view == null) ? null : view.getAttribute(s[1]); + public final File toFile() { + return new File(toString()); } @Override - public final Map readAttributes(String attributes, LinkOption... options) + public final WatchKey register(WatchService watcher, + WatchEvent.Kind... events) throws IOException { - String[] s = split(attributes); - DynamicFileAttributeView view = getFileAttributeView(s[0], options); - if (view == null) - return Collections.emptyMap(); - return view.readAttributes(s[1].split(",")); + return register(watcher, events, new WatchEvent.Modifier[0]); } } diff --git a/src/share/classes/sun/nio/fs/AbstractPoller.java b/src/share/classes/sun/nio/fs/AbstractPoller.java index 25567f3ce305412fa12363f269f0cf58ff2562fc..4bc4ecc29df347b3ae3ccbaac5060e423eb5c23b 100644 --- a/src/share/classes/sun/nio/fs/AbstractPoller.java +++ b/src/share/classes/sun/nio/fs/AbstractPoller.java @@ -92,7 +92,7 @@ abstract class AbstractPoller implements Runnable { /** * Requests, and waits on, poller thread to register given file. */ - final WatchKey register(FileRef dir, + final WatchKey register(Path dir, WatchEvent.Kind[] events, WatchEvent.Modifier... modifiers) throws IOException @@ -102,7 +102,7 @@ abstract class AbstractPoller implements Runnable { throw new NullPointerException(); if (events.length == 0) throw new IllegalArgumentException("No events to register"); - Set> eventSet = new HashSet>(events.length); + Set> eventSet = new HashSet<>(events.length); for (WatchEvent.Kind event: events) { // standard events if (event == StandardWatchEventKind.ENTRY_CREATE || diff --git a/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java b/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java index 2f60db3f54710d483a38c3e640c088fa470091ca..cf36a09ff0a72c61c6db6225c0999a2f6866e087 100644 --- a/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java +++ b/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java @@ -59,8 +59,7 @@ abstract class AbstractUserDefinedFileAttributeView return "user"; } - @Override - public final Object getAttribute(String attribute) throws IOException { + private Object getAttribute(String attribute) throws IOException { int size; try { size = size(attribute); @@ -90,11 +89,11 @@ abstract class AbstractUserDefinedFileAttributeView } @Override - public final Map readAttributes(String[] attributes) + public final Map readAttributes(String[] attributes) throws IOException { // names of attributes to return - List names = new ArrayList(); + List names = new ArrayList<>(); for (String name: attributes) { if (name.equals("*")) { @@ -106,7 +105,7 @@ abstract class AbstractUserDefinedFileAttributeView } // read each value and return in map - Map result = new HashMap(); + Map result = new HashMap<>(); for (String name: names) { Object value = getAttribute(name); if (value != null) diff --git a/src/share/classes/sun/nio/fs/AbstractWatchKey.java b/src/share/classes/sun/nio/fs/AbstractWatchKey.java index c3970d86c05330560599ab9fee050ba5bdc47510..55234ba6528f690cca40eab80454f0c48df30a9b 100644 --- a/src/share/classes/sun/nio/fs/AbstractWatchKey.java +++ b/src/share/classes/sun/nio/fs/AbstractWatchKey.java @@ -32,7 +32,7 @@ import java.util.*; * Base implementation class for watch keys. */ -abstract class AbstractWatchKey extends WatchKey { +abstract class AbstractWatchKey implements WatchKey { /** * Maximum size of event list (in the future this may be tunable) @@ -53,6 +53,9 @@ abstract class AbstractWatchKey extends WatchKey { // reference to watcher private final AbstractWatchService watcher; + // reference to the original directory + private final Path dir; + // key state private State state; @@ -63,8 +66,9 @@ abstract class AbstractWatchKey extends WatchKey { // event for the context is an ENTRY_MODIFY event). private Map> lastModifyEvents; - protected AbstractWatchKey(AbstractWatchService watcher) { + protected AbstractWatchKey(Path dir, AbstractWatchService watcher) { this.watcher = watcher; + this.dir = dir; this.state = State.READY; this.events = new ArrayList>(); this.lastModifyEvents = new HashMap>(); @@ -74,6 +78,13 @@ abstract class AbstractWatchKey extends WatchKey { return watcher; } + /** + * Return the original watchable (Path) + */ + Path watchable() { + return dir; + } + /** * Enqueues this key to the watch service */ @@ -175,7 +186,7 @@ abstract class AbstractWatchKey extends WatchKey { /** * WatchEvent implementation */ - private static class Event extends WatchEvent { + private static class Event implements WatchEvent { private final WatchEvent.Kind kind; private final T context; diff --git a/src/share/classes/sun/nio/fs/AbstractWatchService.java b/src/share/classes/sun/nio/fs/AbstractWatchService.java index ffab46fd645574c7d5bcbe22b0d6b8c50685f4dc..c35e15f4158e71848f102f1c57b15a250e932f0b 100644 --- a/src/share/classes/sun/nio/fs/AbstractWatchService.java +++ b/src/share/classes/sun/nio/fs/AbstractWatchService.java @@ -33,7 +33,7 @@ import java.io.IOException; * Base implementation class for watch services. */ -abstract class AbstractWatchService extends WatchService { +abstract class AbstractWatchService implements WatchService { // signaled keys waiting to be dequeued private final LinkedBlockingDeque pendingKeys = @@ -41,7 +41,7 @@ abstract class AbstractWatchService extends WatchService { // special key to indicate that watch service is closed private final WatchKey CLOSE_KEY = - new AbstractWatchKey(null) { + new AbstractWatchKey(null, null) { @Override public boolean isValid() { return true; @@ -54,7 +54,7 @@ abstract class AbstractWatchService extends WatchService { // used when closing watch service private volatile boolean closed; - private Object closeLock = new Object(); + private final Object closeLock = new Object(); protected AbstractWatchService() { } @@ -93,7 +93,7 @@ abstract class AbstractWatchService extends WatchService { } @Override - public final WatchKey poll() { + public final WatchKey poll() { checkOpen(); WatchKey key = pendingKeys.poll(); checkKey(key); diff --git a/src/share/classes/sun/nio/fs/DynamicFileAttributeView.java b/src/share/classes/sun/nio/fs/DynamicFileAttributeView.java index 963a741b525ee30e632c02682688f7b1d91681d3..f91b8539e9cddb223833dac19c4b16ee38a27c29 100644 --- a/src/share/classes/sun/nio/fs/DynamicFileAttributeView.java +++ b/src/share/classes/sun/nio/fs/DynamicFileAttributeView.java @@ -34,11 +34,6 @@ import java.io.IOException; */ interface DynamicFileAttributeView { - /** - * Reads the value of an attribute. - */ - Object getAttribute(String attribute) throws IOException; - /** * Sets/updates the value of an attribute. */ @@ -47,5 +42,5 @@ interface DynamicFileAttributeView { /** * Reads a set of file attributes as a bulk operation. */ - Map readAttributes(String[] attributes) throws IOException; + Map readAttributes(String[] attributes) throws IOException; } diff --git a/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java b/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java index 977b81f4cfa25cb7904fe102d85aef06f644aece..aae9bd318c114691b289b3067f6f1efa957ec1e0 100644 --- a/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java +++ b/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java @@ -57,13 +57,6 @@ final class FileOwnerAttributeViewImpl return "owner"; } - @Override - public Object getAttribute(String attribute) throws IOException { - if (attribute.equals(OWNER_NAME)) - return getOwner(); - return null; - } - @Override public void setAttribute(String attribute, Object value) throws IOException @@ -77,8 +70,8 @@ final class FileOwnerAttributeViewImpl } @Override - public Map readAttributes(String[] attributes) throws IOException { - Map result = new HashMap(); + public Map readAttributes(String[] attributes) throws IOException { + Map result = new HashMap<>(); for (String attribute: attributes) { if (attribute.equals("*") || attribute.equals(OWNER_NAME)) { result.put(OWNER_NAME, getOwner()); diff --git a/src/share/classes/sun/nio/fs/PollingWatchService.java b/src/share/classes/sun/nio/fs/PollingWatchService.java index e2b2078bd997be5fa38b15f81d6d8241cdd007ad..7cd923842b5c82ef316c2d145531d75cae078b50 100644 --- a/src/share/classes/sun/nio/fs/PollingWatchService.java +++ b/src/share/classes/sun/nio/fs/PollingWatchService.java @@ -146,7 +146,7 @@ class PollingWatchService throws IOException { // check file is a directory and get its file key if possible - BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path); + BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); if (!attrs.isDirectory()) { throw new NotDirectoryException(path.toString()); } @@ -164,7 +164,7 @@ class PollingWatchService watchKey = map.get(fileKey); if (watchKey == null) { // new registration - watchKey = new PollingWatchKey(this, path, fileKey); + watchKey = new PollingWatchKey(path, this, fileKey); map.put(fileKey, watchKey); } else { // update to existing registration @@ -228,7 +228,6 @@ class PollingWatchService * directory and queue keys when entries are added, modified, or deleted. */ private class PollingWatchKey extends AbstractWatchKey { - private final Path dir; private final Object fileKey; // current event set @@ -246,44 +245,28 @@ class PollingWatchService // map of entries in directory private Map entries; - PollingWatchKey(PollingWatchService watcher, - Path dir, - Object fileKey) + PollingWatchKey(Path dir, PollingWatchService watcher, Object fileKey) throws IOException { - super(watcher); - this.dir = dir; + super(dir, watcher); this.fileKey = fileKey; this.valid = true; this.tickCount = 0; this.entries = new HashMap(); // get the initial entries in the directory - DirectoryStream stream = dir.newDirectoryStream(); - try { + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { for (Path entry: stream) { // don't follow links - long lastModified = Attributes - .readBasicFileAttributes(entry, LinkOption.NOFOLLOW_LINKS) - .lastModifiedTime().toMillis(); - entries.put(entry.getName(), - new CacheEntry(lastModified, tickCount)); + long lastModified = + Files.getLastModifiedTime(entry, LinkOption.NOFOLLOW_LINKS).toMillis(); + entries.put(entry.getFileName(), new CacheEntry(lastModified, tickCount)); } - } catch (ConcurrentModificationException cme) { - // thrown if directory iteration fails - Throwable cause = cme.getCause(); - if (cause != null && cause instanceof IOException) - throw (IOException)cause; - throw new AssertionError(cme); - } finally { - stream.close(); + } catch (DirectoryIteratorException e) { + throw e.getCause(); } } - FileRef directory() { - return dir; - } - Object fileKey() { return fileKey; } @@ -342,7 +325,7 @@ class PollingWatchService // open directory DirectoryStream stream = null; try { - stream = dir.newDirectoryStream(); + stream = Files.newDirectoryStream(watchable()); } catch (IOException x) { // directory is no longer accessible so cancel key cancel(); @@ -355,9 +338,8 @@ class PollingWatchService for (Path entry: stream) { long lastModified = 0L; try { - lastModified = Attributes - .readBasicFileAttributes(entry, LinkOption.NOFOLLOW_LINKS) - .lastModifiedTime().toMillis(); + lastModified = + Files.getLastModifiedTime(entry, LinkOption.NOFOLLOW_LINKS).toMillis(); } catch (IOException x) { // unable to get attributes of entry. If file has just // been deleted then we'll report it as deleted on the @@ -366,15 +348,15 @@ class PollingWatchService } // lookup cache - CacheEntry e = entries.get(entry.getName()); + CacheEntry e = entries.get(entry.getFileName()); if (e == null) { // new file found - entries.put(entry.getName(), + entries.put(entry.getFileName(), new CacheEntry(lastModified, tickCount)); // queue ENTRY_CREATE if event enabled if (events.contains(StandardWatchEventKind.ENTRY_CREATE)) { - signalEvent(StandardWatchEventKind.ENTRY_CREATE, entry.getName()); + signalEvent(StandardWatchEventKind.ENTRY_CREATE, entry.getFileName()); continue; } else { // if ENTRY_CREATE is not enabled and ENTRY_MODIFY is @@ -382,7 +364,7 @@ class PollingWatchService // modifications to the file immediately after it is // created. if (events.contains(StandardWatchEventKind.ENTRY_MODIFY)) { - signalEvent(StandardWatchEventKind.ENTRY_MODIFY, entry.getName()); + signalEvent(StandardWatchEventKind.ENTRY_MODIFY, entry.getFileName()); } } continue; @@ -391,15 +373,17 @@ class PollingWatchService // check if file has changed if (e.lastModified != lastModified) { if (events.contains(StandardWatchEventKind.ENTRY_MODIFY)) { - signalEvent(StandardWatchEventKind.ENTRY_MODIFY, entry.getName()); + signalEvent(StandardWatchEventKind.ENTRY_MODIFY, + entry.getFileName()); } } // entry in cache so update poll time e.update(lastModified, tickCount); } - } catch (ConcurrentModificationException x) { - // FIXME - should handle this + } catch (DirectoryIteratorException e) { + // ignore for now; if the directory is no longer accessible + // then the key will be cancelled on the next poll } finally { // close directory stream diff --git a/src/share/classes/sun/security/provider/SeedGenerator.java b/src/share/classes/sun/security/provider/SeedGenerator.java index d66181a614925f4dc9a1cc200a185e073b685145..cb778055b3526343562c7756af045a401607ae73 100644 --- a/src/share/classes/sun/security/provider/SeedGenerator.java +++ b/src/share/classes/sun/security/provider/SeedGenerator.java @@ -63,13 +63,14 @@ package sun.security.provider; * @author Gadi Guy */ -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; import java.security.*; import java.io.*; import java.util.Properties; import java.util.Enumeration; import java.net.*; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Random; import sun.security.util.Debug; @@ -177,37 +178,21 @@ abstract class SeedGenerator { // The temporary dir File f = new File(p.getProperty("java.io.tmpdir")); - - // Go thru files in the tmp dir using NIO's - // DirectoryStream. Fallback to File.list() - // if NIO is not available. - if (NIODirectoryStream.isAvailable()) { - int count = 0; - Iterable stream = - NIODirectoryStream.newDirectoryStream(f); + int count = 0; + try (DirectoryStream stream = Files.newDirectoryStream(f.toPath())) { // We use a Random object to choose what file names // should be used. Otherwise on a machine with too // many files, the same first 1024 files always get // used. Any, We make sure the first 512 files are // always used. Random r = new Random(); - try { - for (Object entry: stream) { - if (count < 512 || r.nextBoolean()) { - md.update(NIODirectoryStream.getName( - entry).getBytes()); - } - if (count++ > 1024) { - break; - } + for (Path entry: stream) { + if (count < 512 || r.nextBoolean()) { + md.update(entry.getFileName().toString().getBytes()); + } + if (count++ > 1024) { + break; } - } finally { - ((Closeable)stream).close(); - } - } else { - String[] sa = f.list(); - for(int i = 0; i < sa.length; i++) { - md.update(sa[i].getBytes()); } } } catch (Exception ex) { @@ -553,77 +538,4 @@ abstract class SeedGenerator { } } - - /** - * A wrapper of NIO DirectoryStream using reflection. - */ - private static class NIODirectoryStream { - private static final Class pathClass = - getClass("java.nio.file.Path"); - - private static final Method toPathMethod = - (pathClass == null) ? null : getMethod(File.class, "toPath"); - private static final Method getNameMethod = - getMethod(pathClass, "getName"); - private static final Method newDirectoryStreamMethod = - getMethod(pathClass, "newDirectoryStream"); - - private static Class getClass(String name) { - try { - return Class.forName(name, true, null); - } catch (ClassNotFoundException e) { - return null; - } - } - - private static Method getMethod(Class clazz, - String name, - Class... paramTypes) { - if (clazz != null) { - try { - return clazz.getMethod(name, paramTypes); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - } else { - return null; - } - } - - static boolean isAvailable() { - return pathClass != null; - } - - static Iterable newDirectoryStream(File dir) throws IOException { - assert pathClass != null; - try { - Object path = toPathMethod.invoke(dir); - return (Iterable)newDirectoryStreamMethod.invoke(path); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof IOException) - throw (IOException)cause; - if (cause instanceof RuntimeException) - throw (RuntimeException)cause; - if (cause instanceof Error) - throw (Error)cause; - throw new AssertionError(e); - } catch (IllegalAccessException iae) { - throw new AssertionError(iae); - } - } - - static String getName(Object path) { - assert pathClass != null; - try { - Object name = getNameMethod.invoke(path); - return name.toString(); - } catch (InvocationTargetException e) { - throw new AssertionError(e); - } catch (IllegalAccessException iae) { - throw new AssertionError(iae); - } - } - } } - diff --git a/src/share/classes/sun/tools/jar/Main.java b/src/share/classes/sun/tools/jar/Main.java index 3b8ea5b95b8aedda0ed0fc3ec54f70610305f6fa..59c758f6cfc183be7263fd44347dd049626d61a3 100644 --- a/src/share/classes/sun/tools/jar/Main.java +++ b/src/share/classes/sun/tools/jar/Main.java @@ -27,6 +27,7 @@ package sun.tools.jar; import java.io.*; import java.nio.file.Path; +import java.nio.file.Files; import java.util.*; import java.util.zip.*; import java.util.jar.*; @@ -1017,17 +1018,17 @@ class Main { Path jarPath = jarFile.toPath(); Path tmpPath = createTempFileInSameDirectoryAs(jarFile).toPath(); try { - if (update(jarPath.newInputStream(), - tmpPath.newOutputStream(), + if (update(Files.newInputStream(jarPath), + Files.newOutputStream(tmpPath), null, index)) { try { - tmpPath.moveTo(jarPath, REPLACE_EXISTING); + Files.move(tmpPath, jarPath, REPLACE_EXISTING); } catch (IOException e) { throw new IOException(getMsg("error.write.file"), e); } } } finally { - tmpPath.deleteIfExists(); + Files.deleteIfExists(tmpPath); } } diff --git a/src/share/sample/nio/file/AclEdit.java b/src/share/sample/nio/file/AclEdit.java index c0088ca0990506ad799103c094f3fb5b30486ca5..0910e888a70f3a59905c06f213cefb1f118fa843 100644 --- a/src/share/sample/nio/file/AclEdit.java +++ b/src/share/sample/nio/file/AclEdit.java @@ -239,7 +239,7 @@ public class AclEdit { // read file's ACL AclFileAttributeView view = - file.getFileAttributeView(AclFileAttributeView.class); + Files.getFileAttributeView(file, AclFileAttributeView.class); if (view == null) { System.err.println("ACLs not supported on this platform"); System.exit(-1); diff --git a/src/share/sample/nio/file/Chmod.java b/src/share/sample/nio/file/Chmod.java index ae8feeeae044e8ba482872387366b74ff6a02cee..7c4d50e93efa0665ba3dae21868b7873b78308a6 100644 --- a/src/share/sample/nio/file/Chmod.java +++ b/src/share/sample/nio/file/Chmod.java @@ -264,11 +264,10 @@ public class Chmod { /** * Changes the permissions of the file using the given Changer. */ - static void chmod(FileRef file, Changer changer) { + static void chmod(Path file, Changer changer) { try { - Set perms = Attributes - .readPosixFileAttributes(file).permissions(); - Attributes.setPosixFilePermissions(file, changer.change(perms)); + Set perms = Files.getPosixFilePermissions(file); + Files.setPosixFilePermissions(file, changer.change(perms)); } catch (IOException x) { System.err.println(x); } @@ -277,7 +276,7 @@ public class Chmod { /** * Changes the permission of each file and directory visited */ - static class TreeVisitor implements FileVisitor { + static class TreeVisitor implements FileVisitor { private final Changer changer; TreeVisitor(Changer changer) { @@ -285,26 +284,26 @@ public class Chmod { } @Override - public FileVisitResult preVisitDirectory(FileRef dir, BasicFileAttributes attrs) { + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { chmod(dir, changer); return CONTINUE; } @Override - public FileVisitResult visitFile(FileRef file, BasicFileAttributes attrs) { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { chmod(file, changer); return CONTINUE; } @Override - public FileVisitResult postVisitDirectory(FileRef dir, IOException exc) { + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { if (exc != null) System.err.println("WARNING: " + exc); return CONTINUE; } @Override - public FileVisitResult visitFileFailed(FileRef file, IOException exc) { + public FileVisitResult visitFileFailed(Path file, IOException exc) { System.err.println("WARNING: " + exc); return CONTINUE; } diff --git a/src/share/sample/nio/file/Copy.java b/src/share/sample/nio/file/Copy.java index eb3d5a06d0370c6071d38b37d247536f5a3aded0..38062c4b87530bda7e1d6e66b0c05108967da019 100644 --- a/src/share/sample/nio/file/Copy.java +++ b/src/share/sample/nio/file/Copy.java @@ -45,7 +45,7 @@ public class Copy { /** * Returns {@code true} if okay to overwrite a file ("cp -i") */ - static boolean okayToOverwrite(FileRef file) { + static boolean okayToOverwrite(Path file) { String answer = System.console().readLine("overwrite %s (yes/no)? ", file); return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes")); } @@ -59,9 +59,9 @@ public class Copy { CopyOption[] options = (preserve) ? new CopyOption[] { COPY_ATTRIBUTES, REPLACE_EXISTING } : new CopyOption[] { REPLACE_EXISTING }; - if (!prompt || target.notExists() || okayToOverwrite(target)) { + if (!prompt || Files.notExists(target) || okayToOverwrite(target)) { try { - source.copyTo(target, options); + Files.copy(source, target, options); } catch (IOException x) { System.err.format("Unable to copy: %s: %s%n", source, x); } @@ -93,7 +93,7 @@ public class Copy { Path newdir = target.resolve(source.relativize(dir)); try { - dir.copyTo(newdir, options); + Files.copy(dir, newdir, options); } catch (FileAlreadyExistsException x) { // ignore } catch (IOException x) { @@ -116,8 +116,8 @@ public class Copy { if (exc == null && preserve) { Path newdir = target.resolve(source.relativize(dir)); try { - BasicFileAttributes attrs = Attributes.readBasicFileAttributes(dir); - Attributes.setLastModifiedTime(newdir, attrs.lastModifiedTime()); + FileTime time = Files.getLastModifiedTime(dir); + Files.setLastModifiedTime(newdir, time); } catch (IOException x) { System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x); } @@ -180,16 +180,11 @@ public class Copy { Path target = Paths.get(args[argi]); // check if target is a directory - boolean isDir = false; - try { - isDir = Attributes.readBasicFileAttributes(target).isDirectory(); - } catch (IOException x) { - // ignore (probably target does not exist) - } + boolean isDir = Files.isDirectory(target); // copy each source file/directory to target for (i=0; i 20) { @@ -66,7 +64,7 @@ public class DiskUsage { } } else { for (String file: args) { - FileStore store = Paths.get(file).getFileStore(); + FileStore store = Files.getFileStore(Paths.get(file)); printFileStore(store); } } diff --git a/src/share/sample/nio/file/FileType.java b/src/share/sample/nio/file/FileType.java index c4713f1a532751e7cb2936bd90adf8df844af482..71451614b07a762edef4e75e1ae51ba41bee55d0 100644 --- a/src/share/sample/nio/file/FileType.java +++ b/src/share/sample/nio/file/FileType.java @@ -30,7 +30,6 @@ */ import java.nio.file.*; -import java.nio.file.attribute.*; import java.io.IOException; public class FileType { @@ -41,10 +40,8 @@ public class FileType { } for (String arg: args) { Path file = Paths.get(arg); - BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file); - String type; - if (attrs.isDirectory()) { + if (Files.isDirectory(file)) { type = "directory"; } else { type = Files.probeContentType(file); diff --git a/src/share/sample/nio/file/WatchDir.java b/src/share/sample/nio/file/WatchDir.java index f2017256e9ebf0f1f650928e337d54b7882aa352..33c15dd0c042fb003d6e7447b11819d68028718a 100644 --- a/src/share/sample/nio/file/WatchDir.java +++ b/src/share/sample/nio/file/WatchDir.java @@ -58,7 +58,7 @@ public class WatchDir { private void register(Path dir) throws IOException { WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); if (trace) { - FileRef prev = keys.get(key); + Path prev = keys.get(key); if (prev == null) { System.out.format("register: %s\n", dir); } else { @@ -147,7 +147,7 @@ public class WatchDir { // register it and its sub-directories if (recursive && (kind == ENTRY_CREATE)) { try { - if (Attributes.readBasicFileAttributes(child, NOFOLLOW_LINKS).isDirectory()) { + if (Files.isDirectory(child, NOFOLLOW_LINKS)) { registerAll(child); } } catch (IOException x) { diff --git a/src/share/sample/nio/file/Xdd.java b/src/share/sample/nio/file/Xdd.java index 8796a174049c472f38119044d20e040382fbd264..7551121a924a5b308c0b9a319b8040bd386f0eda 100644 --- a/src/share/sample/nio/file/Xdd.java +++ b/src/share/sample/nio/file/Xdd.java @@ -58,14 +58,14 @@ public class Xdd { Paths.get(args[0]) : Paths.get(args[2]); // check that user defined attributes are supported by the file store - FileStore store = file.getFileStore(); + FileStore store = Files.getFileStore(file); if (!store.supportsFileAttributeView(UserDefinedFileAttributeView.class)) { System.err.format("UserDefinedFileAttributeView not supported on %s\n", store); System.exit(-1); } - UserDefinedFileAttributeView view = file. - getFileAttributeView(UserDefinedFileAttributeView.class); + UserDefinedFileAttributeView view = + Files.getFileAttributeView(file, UserDefinedFileAttributeView.class); // list user defined attributes if (args.length == 1) { diff --git a/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java b/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java index 3b1925b8697b6d04d3c771ecc2ef14fa5d892029..8e06835570f8720a83800df12b3d48540b136743 100644 --- a/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java +++ b/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java @@ -25,7 +25,7 @@ package sun.nio.fs; -import java.nio.file.FileRef; +import java.nio.file.Path; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; @@ -57,7 +57,7 @@ public class GnomeFileTypeDetector } @Override - public String implProbeContentType(FileRef obj) throws IOException { + public String implProbeContentType(Path obj) throws IOException { if (!gioAvailable && !gnomeVfsAvailable) return null; if (!(obj instanceof UnixPath)) diff --git a/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java b/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java index c51fe6b959d222508d2a34e5a951cc9cdb2ed990..4499a08924c51d77479a9352a8811d292d714bcc 100644 --- a/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java +++ b/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java @@ -66,19 +66,6 @@ class LinuxDosFileAttributeView return "dos"; } - @Override - public Object getAttribute(String attribute) throws IOException { - if (attribute.equals(READONLY_NAME)) - return readAttributes().isReadOnly(); - if (attribute.equals(ARCHIVE_NAME)) - return readAttributes().isArchive(); - if (attribute.equals(SYSTEM_NAME)) - return readAttributes().isSystem(); - if (attribute.equals(HIDDEN_NAME)) - return readAttributes().isHidden(); - return super.getAttribute(attribute); - } - @Override public void setAttribute(String attribute, Object value) throws IOException @@ -103,7 +90,7 @@ class LinuxDosFileAttributeView } @Override - public Map readAttributes(String[] attributes) + public Map readAttributes(String[] attributes) throws IOException { AttributesBuilder builder = AttributesBuilder.create(attributes); diff --git a/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java b/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java index 225c5abab35484979f3df7647e9cd3873ce6d2f3..b8b8c30f936e80a3114ce23aa0b69041cd33a8b2 100644 --- a/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java +++ b/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java @@ -26,7 +26,6 @@ package sun.nio.fs; import java.nio.file.*; -import java.nio.file.attribute.*; import java.io.IOException; import java.util.*; import java.security.AccessController; @@ -76,39 +75,14 @@ class LinuxFileSystem extends UnixFileSystem { } } - @Override - @SuppressWarnings("unchecked") - public V newFileAttributeView(Class view, - UnixPath file, - LinkOption... options) - { - if (view == DosFileAttributeView.class) - return (V) new LinuxDosFileAttributeView(file, followLinks(options)); - if (view == UserDefinedFileAttributeView.class) - return (V) new LinuxUserDefinedFileAttributeView(file, followLinks(options)); - return super.newFileAttributeView(view, file, options); - } - - @Override - @SuppressWarnings("unchecked") - public DynamicFileAttributeView newFileAttributeView(String name, - UnixPath file, - LinkOption... options) - { - if (name.equals("dos")) - return new LinuxDosFileAttributeView(file, followLinks(options)); - if (name.equals("user")) - return new LinuxUserDefinedFileAttributeView(file, followLinks(options)); - return super.newFileAttributeView(name, file, options); - } // lazy initialization of the list of supported attribute views private static class SupportedFileFileAttributeViewsHolder { static final Set supportedFileAttributeViews = supportedFileAttributeViews(); private static Set supportedFileAttributeViews() { - Set result = new HashSet(); - result.addAll(UnixFileSystem.standardFileAttributeViews()); + Set result = new HashSet<>(); + result.addAll(standardFileAttributeViews()); // additional Linux-specific views result.add("dos"); result.add("user"); @@ -130,7 +104,7 @@ class LinuxFileSystem extends UnixFileSystem { * Returns object to iterate over the mount entries in the given fstab file. */ Iterable getMountEntries(String fstab) { - ArrayList entries = new ArrayList(); + ArrayList entries = new ArrayList<>(); try { long fp = setmntent(fstab.getBytes(), "r".getBytes()); try { @@ -159,10 +133,7 @@ class LinuxFileSystem extends UnixFileSystem { return getMountEntries("/etc/mtab"); } - @Override - FileStore getFileStore(UnixPath path) throws IOException { - return new LinuxFileStore(path); - } + @Override FileStore getFileStore(UnixMountEntry entry) throws IOException { diff --git a/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java b/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java index 1cb2772be3071ff517cbe02234cd4f1871d59430..6659ff5ede48f5871524e7697db056d53b87df54 100644 --- a/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java +++ b/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java @@ -25,6 +25,10 @@ package sun.nio.fs; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; + /** * Linux implementation of FileSystemProvider */ @@ -38,4 +42,58 @@ public class LinuxFileSystemProvider extends UnixFileSystemProvider { LinuxFileSystem newFileSystem(String dir) { return new LinuxFileSystem(this, dir); } + + @Override + LinuxFileStore getFileStore(UnixPath path) throws IOException { + return new LinuxFileStore(path); + } + + @Override + @SuppressWarnings("unchecked") + public V getFileAttributeView(Path obj, + Class type, + LinkOption... options) + { + if (type == DosFileAttributeView.class) { + return (V) new LinuxDosFileAttributeView(UnixPath.toUnixPath(obj), + followLinks(options)); + } + if (type == UserDefinedFileAttributeView.class) { + return (V) new LinuxUserDefinedFileAttributeView(UnixPath.toUnixPath(obj), + followLinks(options)); + } + return super.getFileAttributeView(obj, type, options); + } + + @Override + public DynamicFileAttributeView getFileAttributeView(Path obj, + String name, + LinkOption... options) + { + if (name.equals("dos")) { + return new LinuxDosFileAttributeView(UnixPath.toUnixPath(obj), + followLinks(options)); + } + if (name.equals("user")) { + return new LinuxUserDefinedFileAttributeView(UnixPath.toUnixPath(obj), + followLinks(options)); + } + return super.getFileAttributeView(obj, name, options); + } + + @Override + @SuppressWarnings("unchecked") + public A readAttributes(Path file, + Class type, + LinkOption... options) + throws IOException + { + if (type == DosFileAttributes.class) { + DosFileAttributeView view = + getFileAttributeView(file, DosFileAttributeView.class, options); + return (A) view.readAttributes(); + } else { + return super.readAttributes(file, type, options); + } + } } diff --git a/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java b/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java index dfe19ea570e8f032c5f13fb8b57ba0f037c7d60c..14bfbcc2e1e02ddb0daccbee6ff177ba4a252d06 100644 --- a/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java +++ b/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java @@ -63,7 +63,7 @@ class LinuxUserDefinedFileAttributeView // Parses buffer as array of NULL-terminated C strings. private List asList(long address, int size) { - final List list = new ArrayList(); + List list = new ArrayList<>(); int start = 0; int pos = 0; while (pos < size) { diff --git a/src/solaris/classes/sun/nio/fs/LinuxWatchService.java b/src/solaris/classes/sun/nio/fs/LinuxWatchService.java index 9127a372d43691a17a57ae5e93002313b0361469..bca96756325908a7c41fd095215cd88d1cd166d2 100644 --- a/src/solaris/classes/sun/nio/fs/LinuxWatchService.java +++ b/src/solaris/classes/sun/nio/fs/LinuxWatchService.java @@ -102,8 +102,8 @@ class LinuxWatchService // watch descriptor private volatile int wd; - LinuxWatchKey(LinuxWatchService watcher, int ifd, int wd) { - super(watcher); + LinuxWatchKey(UnixPath dir, LinuxWatchService watcher, int ifd, int wd) { + super(dir, watcher); this.ifd = ifd; this.wd = wd; } @@ -266,7 +266,7 @@ class LinuxWatchService // ensure watch descriptor is in map LinuxWatchKey key = wdToKey.get(wd); if (key == null) { - key = new LinuxWatchKey(watcher, ifd, wd); + key = new LinuxWatchKey(dir, watcher, ifd, wd); wdToKey.put(wd, key); } return key; diff --git a/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java b/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java index 285aeca461946929f467ac7534f757a79694accb..5fa71242b81d9fb5525e8f0649e90eef917b6d72 100644 --- a/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java +++ b/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java @@ -198,7 +198,7 @@ class SolarisAclFileAttributeView * Decode the buffer, returning an ACL */ private static List decode(long address, int n) { - ArrayList acl = new ArrayList(n); + ArrayList acl = new ArrayList<>(n); for (int i=0; i aceMask = new HashSet(); + Set aceMask = EnumSet.noneOf(AclEntryPermission.class); if ((mask & ACE_READ_DATA) > 0) aceMask.add(AclEntryPermission.READ_DATA); if ((mask & ACE_WRITE_DATA) > 0) @@ -274,7 +274,7 @@ class SolarisAclFileAttributeView if ((mask & ACE_SYNCHRONIZE) > 0) aceMask.add(AclEntryPermission.SYNCHRONIZE); - HashSet aceFlags = new HashSet(); + Set aceFlags = EnumSet.noneOf(AclEntryFlag.class); if ((flags & ACE_FILE_INHERIT_ACE) > 0) aceFlags.add(AclEntryFlag.FILE_INHERIT); if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0) diff --git a/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java b/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java index 9618e42812c48b3e0efbc552b3ce9b4e45dcfc8d..516d983c259840da108f6175e03afc93d4d50adc 100644 --- a/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java +++ b/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java @@ -26,7 +26,6 @@ package sun.nio.fs; import java.nio.file.*; -import java.nio.file.attribute.*; import java.io.IOException; import java.util.*; import java.security.AccessController; @@ -71,38 +70,14 @@ class SolarisFileSystem extends UnixFileSystem { } } - @Override - @SuppressWarnings("unchecked") - public V newFileAttributeView(Class view, - UnixPath file, LinkOption... options) - { - if (view == AclFileAttributeView.class) - return (V) new SolarisAclFileAttributeView(file, followLinks(options)); - if (view == UserDefinedFileAttributeView.class) { - return(V) new SolarisUserDefinedFileAttributeView(file, followLinks(options)); - } - return super.newFileAttributeView(view, file, options); - } - - @Override - protected DynamicFileAttributeView newFileAttributeView(String name, - UnixPath file, - LinkOption... options) - { - if (name.equals("acl")) - return new SolarisAclFileAttributeView(file, followLinks(options)); - if (name.equals("user")) - return new SolarisUserDefinedFileAttributeView(file, followLinks(options)); - return super.newFileAttributeView(name, file, options); - } // lazy initialization of the list of supported attribute views private static class SupportedFileFileAttributeViewsHolder { static final Set supportedFileAttributeViews = supportedFileAttributeViews(); private static Set supportedFileAttributeViews() { - Set result = new HashSet(); - result.addAll(UnixFileSystem.standardFileAttributeViews()); + Set result = new HashSet<>(); + result.addAll(standardFileAttributeViews()); // additional Solaris-specific views result.add("acl"); result.add("user"); @@ -126,7 +101,7 @@ class SolarisFileSystem extends UnixFileSystem { */ @Override Iterable getMountEntries() { - ArrayList entries = new ArrayList(); + ArrayList entries = new ArrayList<>(); try { UnixPath mnttab = new UnixPath(this, "/etc/mnttab"); long fp = fopen(mnttab, "r"); @@ -147,11 +122,6 @@ class SolarisFileSystem extends UnixFileSystem { return entries; } - @Override - FileStore getFileStore(UnixPath path) throws IOException { - return new SolarisFileStore(path); - } - @Override FileStore getFileStore(UnixMountEntry entry) throws IOException { return new SolarisFileStore(this, entry); diff --git a/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java b/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java index 70f5577fc8b40f94a241224d3fe2612b11b620fd..98c3ae8699ca580bf37a26b26a7e763f649be1e9 100644 --- a/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java +++ b/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java @@ -25,6 +25,10 @@ package sun.nio.fs; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.io.IOException; + /** * Solaris implementation of FileSystemProvider */ @@ -38,4 +42,41 @@ public class SolarisFileSystemProvider extends UnixFileSystemProvider { SolarisFileSystem newFileSystem(String dir) { return new SolarisFileSystem(this, dir); } + + @Override + SolarisFileStore getFileStore(UnixPath path) throws IOException { + return new SolarisFileStore(path); + } + + + @Override + @SuppressWarnings("unchecked") + public V getFileAttributeView(Path obj, + Class type, + LinkOption... options) + { + if (type == AclFileAttributeView.class) { + return (V) new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj), + followLinks(options)); + } + if (type == UserDefinedFileAttributeView.class) { + return(V) new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj), + followLinks(options)); + } + return super.getFileAttributeView(obj, type, options); + } + + @Override + public DynamicFileAttributeView getFileAttributeView(Path obj, + String name, + LinkOption... options) + { + if (name.equals("acl")) + return new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj), + followLinks(options)); + if (name.equals("user")) + return new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj), + followLinks(options)); + return super.getFileAttributeView(obj, name, options); + } } diff --git a/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java b/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java index 60c9da167dc253d7df744709c6b448f85800f782..6148f4109f2a0144d865c6b420132254a354ad08 100644 --- a/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java +++ b/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java @@ -83,7 +83,7 @@ class SolarisUserDefinedFileAttributeView } // read list of extended attributes - final List list = new ArrayList(); + List list = new ArrayList<>(); try { byte[] name; while ((name = readdir(dp)) != null) { diff --git a/src/solaris/classes/sun/nio/fs/SolarisWatchService.java b/src/solaris/classes/sun/nio/fs/SolarisWatchService.java index 5b9f98134b65f66fca74e630b9a643aaab9fe811..68296bc34e506f53ad76f6be3b665a999cac8e3a 100644 --- a/src/solaris/classes/sun/nio/fs/SolarisWatchService.java +++ b/src/solaris/classes/sun/nio/fs/SolarisWatchService.java @@ -128,7 +128,6 @@ class SolarisWatchService private class SolarisWatchKey extends AbstractWatchKey implements DirectoryNode { - private final UnixPath dir; private final UnixFileKey fileKey; // pointer to native file_obj object @@ -147,15 +146,14 @@ class SolarisWatchService long object, Set> events) { - super(watcher); - this.dir = dir; + super(dir, watcher); this.fileKey = fileKey; this.object = object; this.events = events; } - UnixPath getFileRef() { - return dir; + UnixPath getDirectory() { + return (UnixPath)watchable(); } UnixFileKey getFileKey() { @@ -487,7 +485,7 @@ class SolarisWatchService */ void processDirectoryEvents(SolarisWatchKey key, int mask) { if ((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) { - registerChildren(key.getFileRef(), key, + registerChildren(key.getDirectory(), key, key.events().contains(StandardWatchEventKind.ENTRY_CREATE)); } } @@ -524,7 +522,7 @@ class SolarisWatchService boolean removed = true; try { UnixFileAttributes - .get(key.getFileRef().resolve(node.name()), false); + .get(key.getDirectory().resolve(node.name()), false); removed = false; } catch (UnixException x) { } @@ -554,14 +552,14 @@ class SolarisWatchService DirectoryStream stream = null; try { - stream = dir.newDirectoryStream(); + stream = Files.newDirectoryStream(dir); } catch (IOException x) { // nothing we can do return; } try { for (Path entry: stream) { - Path name = entry.getName(); + Path name = entry.getFileName(); // skip entry if already registered if (parent.getChild(name) != null) @@ -582,9 +580,9 @@ class SolarisWatchService } // create node - EntryNode node = new EntryNode(object, entry.getName(), parent); + EntryNode node = new EntryNode(object, entry.getFileName(), parent); // tell the parent about it - parent.addChild(entry.getName(), node); + parent.addChild(entry.getFileName(), node); object2Node.put(object, node); } } catch (ConcurrentModificationException x) { diff --git a/src/solaris/classes/sun/nio/fs/UnixCopyFile.java b/src/solaris/classes/sun/nio/fs/UnixCopyFile.java index ecb7e189923d96cb87fb79a023e1798d42cbb179..9a666c167eeb6b777f0786e5d50f381c8b2287b9 100644 --- a/src/solaris/classes/sun/nio/fs/UnixCopyFile.java +++ b/src/solaris/classes/sun/nio/fs/UnixCopyFile.java @@ -237,7 +237,7 @@ class UnixCopyFile { fo = open(target, (O_WRONLY | O_CREAT | - O_TRUNC), + O_EXCL), attrs.mode()); } catch (UnixException x) { x.rethrowAsIOException(target); @@ -435,10 +435,8 @@ class UnixCopyFile { if (targetAttrs.isDirectory() && (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) { - throw new FileAlreadyExistsException( - source.getPathForExecptionMessage(), - target.getPathForExecptionMessage(), - x.getMessage()); + throw new DirectoryNotEmptyException( + target.getPathForExecptionMessage()); } x.rethrowAsIOException(target); } @@ -556,10 +554,8 @@ class UnixCopyFile { if (targetAttrs.isDirectory() && (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) { - throw new FileAlreadyExistsException( - source.getPathForExecptionMessage(), - target.getPathForExecptionMessage(), - x.getMessage()); + throw new DirectoryNotEmptyException( + target.getPathForExecptionMessage()); } x.rethrowAsIOException(target); } diff --git a/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java b/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java index 69f3cc52d15f4364b7dd73d4904daa02443d98a0..c21a17707a8e446fead460f4e12a7722d4a9f995 100644 --- a/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java +++ b/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java @@ -148,17 +148,6 @@ class UnixFileAttributeViews { return "posix"; } - @Override - public Object getAttribute(String attribute) throws IOException { - if (attribute.equals(PERMISSIONS_NAME)) - return readAttributes().permissions(); - if (attribute.equals(OWNER_NAME)) - return readAttributes().owner(); - if (attribute.equals(GROUP_NAME)) - return readAttributes().group(); - return super.getAttribute(attribute); - } - @Override @SuppressWarnings("unchecked") public void setAttribute(String attribute, Object value) @@ -195,7 +184,7 @@ class UnixFileAttributeViews { } @Override - public Map readAttributes(String[] attributes) + public Map readAttributes(String[] attributes) throws IOException { AttributesBuilder builder = AttributesBuilder.create(attributes); @@ -307,27 +296,6 @@ class UnixFileAttributeViews { return "unix"; } - @Override - public Object getAttribute(String attribute) throws IOException { - if (attribute.equals(MODE_NAME)) - return readAttributes().mode(); - if (attribute.equals(INO_NAME)) - return readAttributes().ino(); - if (attribute.equals(DEV_NAME)) - return readAttributes().dev(); - if (attribute.equals(RDEV_NAME)) - return readAttributes().rdev(); - if (attribute.equals(NLINK_NAME)) - return readAttributes().nlink(); - if (attribute.equals(UID_NAME)) - return readAttributes().uid(); - if (attribute.equals(GID_NAME)) - return readAttributes().gid(); - if (attribute.equals(CTIME_NAME)) - return readAttributes().ctime(); - return super.getAttribute(attribute); - } - @Override public void setAttribute(String attribute, Object value) throws IOException @@ -348,7 +316,7 @@ class UnixFileAttributeViews { } @Override - public Map readAttributes(String[] attributes) + public Map readAttributes(String[] attributes) throws IOException { AttributesBuilder builder = AttributesBuilder.create(attributes); diff --git a/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java b/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java index b9a81f0315e0924dc848d0e10e020221cba38789..966712e0cf16a2233a4790d78decde9c44b4fe2b 100644 --- a/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java +++ b/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java @@ -124,7 +124,7 @@ class UnixFileAttributes @Override public FileTime creationTime() { - return null; + return lastModifiedTime(); } @Override @@ -194,7 +194,7 @@ class UnixFileAttributes @Override public Set permissions() { int bits = (st_mode & UnixConstants.S_IAMB); - HashSet perms = new HashSet(); + HashSet perms = new HashSet<>(); if ((bits & UnixConstants.S_IRUSR) > 0) perms.add(PosixFilePermission.OWNER_READ); diff --git a/src/solaris/classes/sun/nio/fs/UnixFileStore.java b/src/solaris/classes/sun/nio/fs/UnixFileStore.java index 46e09c6d7b1a4fb7a0a5e8480d401d6f1976e141..080c2c0c2fd62915e9ae5e71d4a82d5bf63bb72d 100644 --- a/src/solaris/classes/sun/nio/fs/UnixFileStore.java +++ b/src/solaris/classes/sun/nio/fs/UnixFileStore.java @@ -103,28 +103,50 @@ abstract class UnixFileStore return entry.isReadOnly(); } + // uses statvfs to read the file system information + private UnixFileStoreAttributes readAttributes() throws IOException { + try { + return UnixFileStoreAttributes.get(file); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compile happy + } + } + + @Override + public long getTotalSpace() throws IOException { + UnixFileStoreAttributes attrs = readAttributes(); + return attrs.blockSize() * attrs.totalBlocks(); + } + + @Override + public long getUsableSpace() throws IOException { + UnixFileStoreAttributes attrs = readAttributes(); + return attrs.blockSize() * attrs.availableBlocks(); + } + + @Override + public long getUnallocatedSpace() throws IOException { + UnixFileStoreAttributes attrs = readAttributes(); + return attrs.blockSize() * attrs.freeBlocks(); + } + @Override - @SuppressWarnings("unchecked") public V getFileStoreAttributeView(Class view) { if (view == null) throw new NullPointerException(); - if (view == FileStoreSpaceAttributeView.class) - return (V) new UnixFileStoreSpaceAttributeView(this); return (V) null; } @Override public Object getAttribute(String attribute) throws IOException { - if (attribute.equals("space:totalSpace")) - return new UnixFileStoreSpaceAttributeView(this) - .readAttributes().totalSpace(); - if (attribute.equals("space:usableSpace")) - return new UnixFileStoreSpaceAttributeView(this) - .readAttributes().usableSpace(); - if (attribute.equals("space:unallocatedSpace")) - return new UnixFileStoreSpaceAttributeView(this) - .readAttributes().unallocatedSpace(); + if (attribute.equals("totalSpace")) + return getTotalSpace(); + if (attribute.equals("usableSpace")) + return getUsableSpace(); + if (attribute.equals("unallocatedSpace")) + return getUnallocatedSpace(); throw new UnsupportedOperationException("'" + attribute + "' not recognized"); } @@ -181,50 +203,6 @@ abstract class UnixFileStore return sb.toString(); } - private static class UnixFileStoreSpaceAttributeView - implements FileStoreSpaceAttributeView - { - private final UnixFileStore fs; - - UnixFileStoreSpaceAttributeView(UnixFileStore fs) { - this.fs = fs; - } - - @Override - public String name() { - return "space"; - } - - @Override - public FileStoreSpaceAttributes readAttributes() - throws IOException - { - UnixPath file = fs.file(); - final UnixFileStoreAttributes attrs; - try { - attrs = UnixFileStoreAttributes.get(file); - } catch (UnixException x) { - x.rethrowAsIOException(file); - return null; // keep compile happy - } - - return new FileStoreSpaceAttributes() { - @Override - public long totalSpace() { - return attrs.blockSize() * attrs.totalBlocks(); - } - @Override - public long usableSpace() { - return attrs.blockSize() * attrs.availableBlocks(); - } - @Override - public long unallocatedSpace() { - return attrs.blockSize() * attrs.freeBlocks(); - } - }; - } - } - // -- fstypes.properties -- private static final Object loadLock = new Object(); @@ -277,11 +255,8 @@ abstract class UnixFileStore String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties"; Path file = Paths.get(fstypes); try { - ReadableByteChannel rbc = file.newByteChannel(); - try { + try (ReadableByteChannel rbc = Files.newByteChannel(file)) { result.load(Channels.newReader(rbc, "UTF-8")); - } finally { - rbc.close(); } } catch (IOException x) { } diff --git a/src/solaris/classes/sun/nio/fs/UnixFileSystem.java b/src/solaris/classes/sun/nio/fs/UnixFileSystem.java index 7068a25fc83c57579eb502512e1af5fe17647fcc..96c6e4a4cce9ff9994819e9995db88d76d64dbbb 100644 --- a/src/solaris/classes/sun/nio/fs/UnixFileSystem.java +++ b/src/solaris/classes/sun/nio/fs/UnixFileSystem.java @@ -98,6 +98,10 @@ abstract class UnixFileSystem return false; } + static List standardFileAttributeViews() { + return Arrays.asList("basic", "posix", "unix", "owner"); + } + @Override public final FileSystemProvider provider() { return provider; @@ -168,12 +172,6 @@ abstract class UnixFileSystem */ abstract Iterable getMountEntries(); - /** - * Returns a FileStore to represent the file system where the given file - * reside. - */ - abstract FileStore getFileStore(UnixPath path) throws IOException; - /** * Returns a FileStore to represent the file system for the given mount * mount. @@ -264,7 +262,22 @@ abstract class UnixFileSystem } @Override - public final UnixPath getPath(String path) { + public final Path getPath(String first, String... more) { + String path; + if (more.length == 0) { + path = first; + } else { + StringBuilder sb = new StringBuilder(); + sb.append(first); + for (String segment: more) { + if (segment.length() > 0) { + if (sb.length() > 0) + sb.append('/'); + sb.append(segment); + } + } + path = sb.toString(); + } return new UnixPath(this, path); } @@ -300,77 +313,30 @@ abstract class UnixFileSystem private static final String GLOB_SYNTAX = "glob"; private static final String REGEX_SYNTAX = "regex"; - protected boolean followLinks(LinkOption... options) { - boolean followLinks = true; - for (LinkOption option: options) { - if (option == LinkOption.NOFOLLOW_LINKS) { - followLinks = false; - continue; - } - if (option == null) - throw new NullPointerException(); - throw new AssertionError("Should not get here"); - } - return followLinks; - } - - @SuppressWarnings("unchecked") - protected V newFileAttributeView(Class view, - UnixPath file, - LinkOption... options) - { - if (view == null) - throw new NullPointerException(); - boolean followLinks = followLinks(options); - Class c = view; - if (c == BasicFileAttributeView.class) - return (V) UnixFileAttributeViews.createBasicView(file, followLinks); - if (c == PosixFileAttributeView.class) - return (V) UnixFileAttributeViews.createPosixView(file, followLinks); - if (c == FileOwnerAttributeView.class) - return (V) UnixFileAttributeViews.createOwnerView(file, followLinks); - return (V) null; - } - - static List standardFileAttributeViews() { - return Arrays.asList("basic", "posix", "unix", "owner"); - } - protected DynamicFileAttributeView newFileAttributeView(String name, - UnixPath file, - LinkOption... options) - { - boolean followLinks = followLinks(options); - if (name.equals("basic")) - return UnixFileAttributeViews.createBasicView(file, followLinks); - if (name.equals("posix")) - return UnixFileAttributeViews.createPosixView(file, followLinks); - if (name.equals("unix")) - return UnixFileAttributeViews.createUnixView(file, followLinks); - if (name.equals("owner")) - return UnixFileAttributeViews.createOwnerView(file, followLinks); - return null; - } @Override public final UserPrincipalLookupService getUserPrincipalLookupService() { - return theLookupService; + return LookupService.instance; } - private static final UserPrincipalLookupService theLookupService = - new UserPrincipalLookupService() { - @Override - public UserPrincipal lookupPrincipalByName(String name) - throws IOException - { - return UnixUserPrincipals.lookupUser(name); - } + private static class LookupService { + static final UserPrincipalLookupService instance = + new UserPrincipalLookupService() { + @Override + public UserPrincipal lookupPrincipalByName(String name) + throws IOException + { + return UnixUserPrincipals.lookupUser(name); + } + + @Override + public GroupPrincipal lookupPrincipalByGroupName(String group) + throws IOException + { + return UnixUserPrincipals.lookupGroup(group); + } + }; + } - @Override - public GroupPrincipal lookupPrincipalByGroupName(String group) - throws IOException - { - return UnixUserPrincipals.lookupGroup(group); - } - }; } diff --git a/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java b/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java index aae884aa340d1b24f3148a41c4f943d9642e65ff..8ec672a306bbca65911ae715730de5aa6effeff5 100644 --- a/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java +++ b/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java @@ -27,21 +27,25 @@ package sun.nio.fs; import java.nio.file.*; import java.nio.file.attribute.*; -import java.nio.file.spi.FileSystemProvider; import java.nio.channels.*; import java.net.URI; import java.util.concurrent.ExecutorService; import java.io.IOException; +import java.io.FilePermission; import java.util.*; +import java.security.AccessController; import sun.nio.ch.ThreadPool; +import sun.security.util.SecurityConstants; +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.UnixConstants.*; /** * Base implementation of FileSystemProvider */ public abstract class UnixFileSystemProvider - extends FileSystemProvider + extends AbstractFileSystemProvider { private static final String USER_DIR = "user.dir"; private final UnixFileSystem theFileSystem; @@ -93,7 +97,7 @@ public abstract class UnixFileSystemProvider return UnixUriUtils.fromUri(theFileSystem, uri); } - protected UnixPath checkPath(Path obj) { + UnixPath checkPath(Path obj) { if (obj == null) throw new NullPointerException(); if (!(obj instanceof UnixPath)) @@ -101,6 +105,76 @@ public abstract class UnixFileSystemProvider return (UnixPath)obj; } + boolean followLinks(LinkOption... options) { + boolean followLinks = true; + for (LinkOption option: options) { + if (option == LinkOption.NOFOLLOW_LINKS) { + followLinks = false; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new AssertionError("Should not get here"); + } + return followLinks; + } + + @Override + @SuppressWarnings("unchecked") + public V getFileAttributeView(Path obj, + Class type, + LinkOption... options) + { + UnixPath file = UnixPath.toUnixPath(obj); + boolean followLinks = followLinks(options); + if (type == BasicFileAttributeView.class) + return (V) UnixFileAttributeViews.createBasicView(file, followLinks); + if (type == PosixFileAttributeView.class) + return (V) UnixFileAttributeViews.createPosixView(file, followLinks); + if (type == FileOwnerAttributeView.class) + return (V) UnixFileAttributeViews.createOwnerView(file, followLinks); + if (type == null) + throw new NullPointerException(); + return (V) null; + } + + @Override + @SuppressWarnings("unchecked") + public A readAttributes(Path file, + Class type, + LinkOption... options) + throws IOException + { + Class view; + if (type == BasicFileAttributes.class) + view = BasicFileAttributeView.class; + else if (type == PosixFileAttributes.class) + view = PosixFileAttributeView.class; + else if (type == null) + throw new NullPointerException(); + else + throw new UnsupportedOperationException(); + return (A) getFileAttributeView(file, view, options).readAttributes(); + } + + @Override + protected DynamicFileAttributeView getFileAttributeView(Path obj, + String name, + LinkOption... options) + { + UnixPath file = UnixPath.toUnixPath(obj); + boolean followLinks = followLinks(options); + if (name.equals("basic")) + return UnixFileAttributeViews.createBasicView(file, followLinks); + if (name.equals("posix")) + return UnixFileAttributeViews.createPosixView(file, followLinks); + if (name.equals("unix")) + return UnixFileAttributeViews.createUnixView(file, followLinks); + if (name.equals("owner")) + return UnixFileAttributeViews.createOwnerView(file, followLinks); + return null; + } + @Override public FileChannel newFileChannel(Path obj, Set options, @@ -136,4 +210,303 @@ public abstract class UnixFileSystemProvider return null; } } + + + @Override + public SeekableByteChannel newByteChannel(Path obj, + Set options, + FileAttribute... attrs) + throws IOException + { + UnixPath file = UnixPath.toUnixPath(obj); + int mode = UnixFileModeAttribute + .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); + try { + return UnixChannelFactory.newFileChannel(file, options, mode); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } + } + + @Override + boolean implDelete(Path obj, boolean failIfNotExists) throws IOException { + UnixPath file = UnixPath.toUnixPath(obj); + file.checkDelete(); + + // need file attributes to know if file is directory + UnixFileAttributes attrs = null; + try { + attrs = UnixFileAttributes.get(file, false); + if (attrs.isDirectory()) { + rmdir(file); + } else { + unlink(file); + } + return true; + } catch (UnixException x) { + // no-op if file does not exist + if (!failIfNotExists && x.errno() == ENOENT) + return false; + + // DirectoryNotEmptyException if not empty + if (attrs != null && attrs.isDirectory() && + (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) + throw new DirectoryNotEmptyException(file.getPathForExecptionMessage()); + + x.rethrowAsIOException(file); + return false; + } + } + + @Override + public void copy(Path source, Path target, CopyOption... options) + throws IOException + { + UnixCopyFile.copy(UnixPath.toUnixPath(source), + UnixPath.toUnixPath(target), + options); + } + + @Override + public void move(Path source, Path target, CopyOption... options) + throws IOException + { + UnixCopyFile.move(UnixPath.toUnixPath(source), + UnixPath.toUnixPath(target), + options); + } + + @Override + public void checkAccess(Path obj, AccessMode... modes) throws IOException { + UnixPath file = UnixPath.toUnixPath(obj); + boolean e = false; + boolean r = false; + boolean w = false; + boolean x = false; + + if (modes.length == 0) { + e = true; + } else { + for (AccessMode mode: modes) { + switch (mode) { + case READ : r = true; break; + case WRITE : w = true; break; + case EXECUTE : x = true; break; + default: throw new AssertionError("Should not get here"); + } + } + } + + int mode = 0; + if (e || r) { + file.checkRead(); + mode |= (r) ? R_OK : F_OK; + } + if (w) { + file.checkWrite(); + mode |= W_OK; + } + if (x) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // not cached + sm.checkExec(file.getPathForPermissionCheck()); + } + mode |= X_OK; + } + try { + access(file, mode); + } catch (UnixException exc) { + exc.rethrowAsIOException(file); + } + } + + @Override + public boolean isSameFile(Path obj1, Path obj2) throws IOException { + UnixPath file1 = UnixPath.toUnixPath(obj1); + if (file1.equals(obj2)) + return true; + if (obj2 == null) + throw new NullPointerException(); + if (!(obj2 instanceof UnixPath)) + return false; + UnixPath file2 = (UnixPath)obj2; + + // check security manager access to both files + file1.checkRead(); + file2.checkRead(); + + UnixFileAttributes attrs1; + UnixFileAttributes attrs2; + try { + attrs1 = UnixFileAttributes.get(file1, true); + } catch (UnixException x) { + x.rethrowAsIOException(file1); + return false; // keep compiler happy + } + try { + attrs2 = UnixFileAttributes.get(file2, true); + } catch (UnixException x) { + x.rethrowAsIOException(file2); + return false; // keep compiler happy + } + return attrs1.isSameFile(attrs2); + } + + @Override + public boolean isHidden(Path obj) { + UnixPath file = UnixPath.toUnixPath(obj); + file.checkRead(); + UnixPath name = file.getFileName(); + if (name == null) + return false; + return (name.asByteArray()[0] == '.'); + } + + /** + * Returns a FileStore to represent the file system where the given file + * reside. + */ + abstract FileStore getFileStore(UnixPath path) throws IOException; + + @Override + public FileStore getFileStore(Path obj) throws IOException { + UnixPath file = UnixPath.toUnixPath(obj); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); + file.checkRead(); + } + return getFileStore(file); + } + + @Override + public void createDirectory(Path obj, FileAttribute... attrs) + throws IOException + { + UnixPath dir = UnixPath.toUnixPath(obj); + dir.checkWrite(); + + int mode = UnixFileModeAttribute + .toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs); + try { + mkdir(dir, mode); + } catch (UnixException x) { + x.rethrowAsIOException(dir); + } + } + + + @Override + public DirectoryStream newDirectoryStream(Path obj, DirectoryStream.Filter filter) + throws IOException + { + UnixPath dir = UnixPath.toUnixPath(obj); + dir.checkRead(); + if (filter == null) + throw new NullPointerException(); + + // can't return SecureDirectoryStream on kernels that don't support + // openat, etc. + if (!supportsAtSysCalls()) { + try { + long ptr = opendir(dir); + return new UnixDirectoryStream(dir, ptr, filter); + } catch (UnixException x) { + if (x.errno() == ENOTDIR) + throw new NotDirectoryException(dir.getPathForExecptionMessage()); + x.rethrowAsIOException(dir); + } + } + + // open directory and dup file descriptor for use by + // opendir/readdir/closedir + int dfd1 = -1; + int dfd2 = -1; + long dp = 0L; + try { + dfd1 = open(dir, O_RDONLY, 0); + dfd2 = dup(dfd1); + dp = fdopendir(dfd1); + } catch (UnixException x) { + if (dfd1 != -1) + UnixNativeDispatcher.close(dfd1); + if (dfd2 != -1) + UnixNativeDispatcher.close(dfd2); + if (x.errno() == UnixConstants.ENOTDIR) + throw new NotDirectoryException(dir.getPathForExecptionMessage()); + x.rethrowAsIOException(dir); + } + return new UnixSecureDirectoryStream(dir, dp, dfd2, filter); + } + + @Override + public void createSymbolicLink(Path obj1, Path obj2, FileAttribute... attrs) + throws IOException + { + UnixPath link = UnixPath.toUnixPath(obj1); + UnixPath target = UnixPath.toUnixPath(obj2); + + // no attributes supported when creating links + if (attrs.length > 0) { + UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE + throw new UnsupportedOperationException("Initial file attributes" + + "not supported when creating symbolic link"); + } + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LinkPermission("symbolic")); + link.checkWrite(); + } + + // create link + try { + symlink(target.asByteArray(), link); + } catch (UnixException x) { + x.rethrowAsIOException(link); + } + } + + @Override + public void createLink(Path obj1, Path obj2) throws IOException { + UnixPath link = UnixPath.toUnixPath(obj1); + UnixPath existing = UnixPath.toUnixPath(obj2); + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LinkPermission("hard")); + link.checkWrite(); + existing.checkWrite(); + } + try { + link(existing, link); + } catch (UnixException x) { + x.rethrowAsIOException(link, existing); + } + } + + @Override + public Path readSymbolicLink(Path obj1) throws IOException { + UnixPath link = UnixPath.toUnixPath(obj1); + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + FilePermission perm = new FilePermission(link.getPathForPermissionCheck(), + SecurityConstants.FILE_READLINK_ACTION); + AccessController.checkPermission(perm); + } + try { + byte[] target = readlink(link); + return new UnixPath(link.getFileSystem(), target); + } catch (UnixException x) { + if (x.errno() == UnixConstants.EINVAL) + throw new NotLinkException(link.getPathForExecptionMessage()); + x.rethrowAsIOException(link); + return null; // keep compiler happy + } + } } diff --git a/src/solaris/classes/sun/nio/fs/UnixPath.java b/src/solaris/classes/sun/nio/fs/UnixPath.java index 1667263c2220ae1d1f0da09a53484f5226f1597b..9ec49b8d37a7131d42a6e8e459f598cdd3d3dfcb 100644 --- a/src/solaris/classes/sun/nio/fs/UnixPath.java +++ b/src/solaris/classes/sun/nio/fs/UnixPath.java @@ -27,15 +27,11 @@ package sun.nio.fs; import java.nio.*; import java.nio.file.*; -import java.nio.file.attribute.*; import java.nio.charset.*; -import java.nio.channels.*; -import java.security.AccessController; import java.io.*; import java.net.URI; import java.util.*; import java.lang.ref.SoftReference; -import sun.security.util.SecurityConstants; import static sun.nio.fs.UnixNativeDispatcher.*; import static sun.nio.fs.UnixConstants.*; @@ -79,8 +75,6 @@ class UnixPath // removes redundant slashes and check input for invalid characters static String normalizeAndCheck(String input) { int n = input.length(); - if (n == 0) - throw new InvalidPathException(input, "Path is empty"); char prevChar = 0; for (int i=0; i < n; i++) { char c = input.charAt(i); @@ -174,7 +168,13 @@ class UnixPath if (getFileSystem().needToResolveAgainstDefaultDirectory()) { return resolve(getFileSystem().defaultDirectory(), path); } else { - return path; + if (!isEmpty()) { + return path; + } else { + // empty path case will access current directory + byte[] here = { '.' }; + return here; + } } } @@ -193,7 +193,7 @@ class UnixPath } // Checks that the given file is a UnixPath - private UnixPath checkPath(FileRef obj) { + static UnixPath toUnixPath(Path obj) { if (obj == null) throw new NullPointerException(); if (!(obj instanceof UnixPath)) @@ -209,12 +209,17 @@ class UnixPath // count names count = 0; index = 0; - while (index < path.length) { - byte c = path[index++]; - if (c != '/') { - count++; - while (index < path.length && path[index] != '/') - index++; + if (isEmpty()) { + // empty path has one name + count = 1; + } else { + while (index < path.length) { + byte c = path[index++]; + if (c != '/') { + count++; + while (index < path.length && path[index] != '/') + index++; + } } } @@ -239,6 +244,16 @@ class UnixPath } } + // returns {@code true} if this path is an empty path + private boolean isEmpty() { + return path.length == 0; + } + + // returns an empty path + private UnixPath emptyPath() { + return new UnixPath(getFileSystem(), new byte[0]); + } + @Override public UnixFileSystem getFileSystem() { return fs; @@ -246,7 +261,7 @@ class UnixPath @Override public UnixPath getRoot() { - if (path[0] == '/') { + if (path.length > 0 && path[0] == '/') { return getFileSystem().rootDirectory(); } else { return null; @@ -254,14 +269,17 @@ class UnixPath } @Override - public UnixPath getName() { + public UnixPath getFileName() { initOffsets(); int count = offsets.length; + + // no elements so no name if (count == 0) - return null; // no elements so no name + return null; - if (count == 1 && path[0] != '/') + // one name element and no root component + if (count == 1 && path.length > 0 && path[0] != '/') return this; int lastOffset = offsets[count-1]; @@ -349,57 +367,58 @@ class UnixPath @Override public boolean isAbsolute() { - return (path[0] == '/'); + return (path.length > 0 && path[0] == '/'); } // Resolve child against given base private static byte[] resolve(byte[] base, byte[] child) { - if (child[0] == '/') + int baseLength = base.length; + int childLength = child.length; + if (childLength == 0) + return base; + if (baseLength == 0 || child[0] == '/') return child; byte[] result; - if (base.length == 1 && base[0] == '/') { - result = new byte[child.length + 1]; + if (baseLength == 1 && base[0] == '/') { + result = new byte[childLength + 1]; result[0] = '/'; - System.arraycopy(child, 0, result, 1, child.length); + System.arraycopy(child, 0, result, 1, childLength); } else { - result = new byte[base.length + 1 + child.length]; - System.arraycopy(base, 0, result, 0, base.length); + result = new byte[baseLength + 1 + childLength]; + System.arraycopy(base, 0, result, 0, baseLength); result[base.length] = '/'; - System.arraycopy(child, 0, result, base.length+1, child.length); + System.arraycopy(child, 0, result, baseLength+1, childLength); } return result; } @Override public UnixPath resolve(Path obj) { - if (obj == null) - return this; - byte[] other = checkPath(obj).path; - if (other[0] == '/') + byte[] other = toUnixPath(obj).path; + if (other.length > 0 && other[0] == '/') return ((UnixPath)obj); byte[] result = resolve(path, other); return new UnixPath(getFileSystem(), result); } - @Override - public UnixPath resolve(String other) { - return resolve(new UnixPath(getFileSystem(), other)); - } - UnixPath resolve(byte[] other) { return resolve(new UnixPath(getFileSystem(), other)); } @Override public UnixPath relativize(Path obj) { - UnixPath other = checkPath(obj); + UnixPath other = toUnixPath(obj); if (other.equals(this)) - return null; + return emptyPath(); // can only relativize paths of the same type if (this.isAbsolute() != other.isAbsolute()) throw new IllegalArgumentException("'other' is different type of Path"); + // this path is the empty path + if (this.isEmpty()) + return other; + int bn = this.getNameCount(); int cn = other.getNameCount(); @@ -419,14 +438,27 @@ class UnixPath if (dotdots == 0) return remainder; + // other is the empty path + boolean isOtherEmpty = other.isEmpty(); + // result is a "../" for each remaining name in base - // followed by the remaining names in other - byte[] result = new byte[dotdots*3 + remainder.path.length]; + // followed by the remaining names in other. If the remainder is + // the empty path then we don't add the final trailing slash. + int len = dotdots*3 + remainder.path.length; + if (isOtherEmpty) { + assert remainder.isEmpty(); + len--; + } + byte[] result = new byte[len]; int pos = 0; while (dotdots > 0) { result[pos++] = (byte)'.'; result[pos++] = (byte)'.'; - result[pos++] = (byte)'/'; + if (isOtherEmpty) { + if (dotdots > 1) result[pos++] = (byte)'/'; + } else { + result[pos++] = (byte)'/'; + } dotdots--; } System.arraycopy(remainder.path, 0, result, pos, remainder.path.length); @@ -457,7 +489,7 @@ class UnixPath int[] size = new int[count]; // length of name int remaining = count; // number of names remaining boolean hasDotDot = false; // has at least one .. - boolean isAbsolute = path[0] == '/'; + boolean isAbsolute = isAbsolute(); // first pass: // 1. compute length of names @@ -542,7 +574,7 @@ class UnixPath // corner case - all names removed if (remaining == 0) { - return isAbsolute ? getFileSystem().rootDirectory() : null; + return isAbsolute ? getFileSystem().rootDirectory() : emptyPath(); } // compute length of result @@ -574,7 +606,7 @@ class UnixPath @Override public boolean startsWith(Path other) { - UnixPath that = checkPath(other); + UnixPath that = toUnixPath(other); // other path is longer if (that.path.length > path.length) @@ -584,8 +616,9 @@ class UnixPath int thatOffsetCount = that.getNameCount(); // other path has no name elements - if (thatOffsetCount == 0 && this.isAbsolute()) - return true; + if (thatOffsetCount == 0 && this.isAbsolute()) { + return that.isEmpty() ? false : true; + } // given path has more elements that this path if (thatOffsetCount > thisOffsetCount) @@ -622,7 +655,7 @@ class UnixPath @Override public boolean endsWith(Path other) { - UnixPath that = checkPath(other); + UnixPath that = toUnixPath(other); int thisLen = path.length; int thatLen = that.path.length; @@ -631,6 +664,10 @@ class UnixPath if (thatLen > thisLen) return false; + // other path is the empty path + if (thisLen > 0 && thatLen == 0) + return false; + // other path is absolute so this path must be absolute if (that.isAbsolute() && !this.isAbsolute()) return false; @@ -721,32 +758,6 @@ class UnixPath return stringValue; } - @Override - public Iterator iterator() { - initOffsets(); - return new Iterator() { - int i = 0; - @Override - public boolean hasNext() { - return (i < offsets.length); - } - @Override - public Path next() { - if (i < offsets.length) { - Path result = getName(i); - i++; - return result; - } else { - throw new NoSuchElementException(); - } - } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - // -- file operations -- // package-private @@ -770,7 +781,6 @@ class UnixPath } } - void checkRead() { SecurityManager sm = System.getSecurityManager(); if (sm != null) @@ -789,296 +799,6 @@ class UnixPath sm.checkDelete(getPathForPermissionCheck()); } - @Override - public FileStore getFileStore() - throws IOException - { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); - checkRead(); - } - return getFileSystem().getFileStore(this); - } - - @Override - public void checkAccess(AccessMode... modes) throws IOException { - boolean e = false; - boolean r = false; - boolean w = false; - boolean x = false; - - if (modes.length == 0) { - e = true; - } else { - for (AccessMode mode: modes) { - switch (mode) { - case READ : r = true; break; - case WRITE : w = true; break; - case EXECUTE : x = true; break; - default: throw new AssertionError("Should not get here"); - } - } - } - - int mode = 0; - if (e || r) { - checkRead(); - mode |= (r) ? R_OK : F_OK; - } - if (w) { - checkWrite(); - mode |= W_OK; - } - if (x) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - // not cached - sm.checkExec(getPathForPermissionCheck()); - } - mode |= X_OK; - } - try { - access(this, mode); - } catch (UnixException exc) { - exc.rethrowAsIOException(this); - } - } - - @Override - void implDelete(boolean failIfNotExists) throws IOException { - checkDelete(); - - // need file attributes to know if file is directory - UnixFileAttributes attrs = null; - try { - attrs = UnixFileAttributes.get(this, false); - if (attrs.isDirectory()) { - rmdir(this); - } else { - unlink(this); - } - } catch (UnixException x) { - // no-op if file does not exist - if (!failIfNotExists && x.errno() == ENOENT) - return; - - // DirectoryNotEmptyException if not empty - if (attrs != null && attrs.isDirectory() && - (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) - throw new DirectoryNotEmptyException(getPathForExecptionMessage()); - - x.rethrowAsIOException(this); - } - } - - @Override - public DirectoryStream newDirectoryStream(DirectoryStream.Filter filter) - throws IOException - { - if (filter == null) - throw new NullPointerException(); - checkRead(); - - // can't return SecureDirectoryStream on kernels that don't support - // openat, etc. - if (!supportsAtSysCalls()) { - try { - long ptr = opendir(this); - return new UnixDirectoryStream(this, ptr, filter); - } catch (UnixException x) { - if (x.errno() == ENOTDIR) - throw new NotDirectoryException(getPathForExecptionMessage()); - x.rethrowAsIOException(this); - } - } - - // open directory and dup file descriptor for use by - // opendir/readdir/closedir - int dfd1 = -1; - int dfd2 = -1; - long dp = 0L; - try { - dfd1 = open(this, O_RDONLY, 0); - dfd2 = dup(dfd1); - dp = fdopendir(dfd1); - } catch (UnixException x) { - if (dfd1 != -1) - close(dfd1); - if (dfd2 != -1) - close(dfd2); - if (x.errno() == UnixConstants.ENOTDIR) - throw new NotDirectoryException(getPathForExecptionMessage()); - x.rethrowAsIOException(this); - } - return new UnixSecureDirectoryStream(this, dp, dfd2, filter); - } - - // invoked by AbstractPath#copyTo - @Override - public void implCopyTo(Path obj, CopyOption... options) - throws IOException - { - UnixPath target = (UnixPath)obj; - UnixCopyFile.copy(this, target, options); - } - - @Override - public void implMoveTo(Path obj, CopyOption... options) - throws IOException - { - UnixPath target = (UnixPath)obj; - UnixCopyFile.move(this, target, options); - } - - @Override - @SuppressWarnings("unchecked") - public V - getFileAttributeView(Class type, LinkOption... options) - { - FileAttributeView view = getFileSystem() - .newFileAttributeView(type, this, options); - if (view == null) - return null; - return (V) view; - } - - @Override - public DynamicFileAttributeView getFileAttributeView(String name, - LinkOption... options) - { - return getFileSystem().newFileAttributeView(name, this, options); - } - - @Override - public Path createDirectory(FileAttribute... attrs) - throws IOException - { - checkWrite(); - - int mode = UnixFileModeAttribute - .toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs); - try { - mkdir(this, mode); - } catch (UnixException x) { - x.rethrowAsIOException(this); - } - return this; - } - - @Override - public SeekableByteChannel newByteChannel(Set options, - FileAttribute... attrs) - throws IOException - { - int mode = UnixFileModeAttribute - .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); - try { - return UnixChannelFactory.newFileChannel(this, options, mode); - } catch (UnixException x) { - x.rethrowAsIOException(this); - return null; // keep compiler happy - } - } - - @Override - public boolean isSameFile(Path obj) throws IOException { - if (this.equals(obj)) - return true; - if (!(obj instanceof UnixPath)) // includes null check - return false; - UnixPath other = (UnixPath)obj; - - // check security manager access to both files - this.checkRead(); - other.checkRead(); - - UnixFileAttributes thisAttrs; - UnixFileAttributes otherAttrs; - try { - thisAttrs = UnixFileAttributes.get(this, true); - } catch (UnixException x) { - x.rethrowAsIOException(this); - return false; // keep compiler happy - } - try { - otherAttrs = UnixFileAttributes.get(other, true); - } catch (UnixException x) { - x.rethrowAsIOException(other); - return false; // keep compiler happy - } - return thisAttrs.isSameFile(otherAttrs); - } - - @Override - public Path createSymbolicLink(Path obj, FileAttribute... attrs) - throws IOException - { - UnixPath target = checkPath(obj); - - // no attributes supported when creating links - if (attrs.length > 0) { - UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE - throw new UnsupportedOperationException("Initial file attributes" + - "not supported when creating symbolic link"); - } - - // permission check - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new LinkPermission("symbolic")); - checkWrite(); - } - - // create link - try { - symlink(target.asByteArray(), this); - } catch (UnixException x) { - x.rethrowAsIOException(this); - } - - return this; - } - - @Override - public Path createLink(Path obj) throws IOException { - UnixPath existing = checkPath(obj); - - // permission check - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new LinkPermission("hard")); - this.checkWrite(); - existing.checkWrite(); - } - try { - link(existing, this); - } catch (UnixException x) { - x.rethrowAsIOException(this, existing); - } - return this; - } - - @Override - public Path readSymbolicLink() throws IOException { - // permission check - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - FilePermission perm = new FilePermission(getPathForPermissionCheck(), - SecurityConstants.FILE_READLINK_ACTION); - AccessController.checkPermission(perm); - } - try { - byte[] target = readlink(this); - return new UnixPath(getFileSystem(), target); - } catch (UnixException x) { - if (x.errno() == UnixConstants.EINVAL) - throw new NotLinkException(getPathForExecptionMessage()); - x.rethrowAsIOException(this); - return null; // keep compiler happy - } - } - @Override public UnixPath toAbsolutePath() { if (isAbsolute()) { @@ -1095,7 +815,7 @@ class UnixPath } @Override - public UnixPath toRealPath(boolean resolveLinks) throws IOException { + public Path toRealPath(boolean resolveLinks) throws IOException { checkRead(); UnixPath absolute = toAbsolutePath(); @@ -1112,8 +832,7 @@ class UnixPath // if resolveLinks is false then eliminate "." and also ".." // where the previous element is not a link. - UnixPath root = getFileSystem().rootDirectory(); - UnixPath result = root; + UnixPath result = fs.rootDirectory(); for (int i=0; i + implements SecureDirectoryStream { private final UnixDirectoryStream ds; private final int dfd; @@ -81,6 +81,20 @@ class UnixSecureDirectoryStream return (UnixPath)obj; } + private boolean followLinks(LinkOption... options) { + boolean followLinks = true; + for (LinkOption option: options) { + if (option == LinkOption.NOFOLLOW_LINKS) { + followLinks = false; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new AssertionError("Should not get here"); + } + return followLinks; + } + /** * Opens sub-directory in this directory */ @@ -91,7 +105,7 @@ class UnixSecureDirectoryStream { UnixPath file = getName(obj); UnixPath child = ds.directory().resolve(file); - boolean followLinks = file.getFileSystem().followLinks(options); + boolean followLinks = followLinks(options); // permission check using name resolved against original path of directory SecurityManager sm = System.getSecurityManager(); @@ -302,7 +316,7 @@ class UnixSecureDirectoryStream LinkOption... options) { UnixPath file = getName(obj); - boolean followLinks = file.getFileSystem().followLinks(options); + boolean followLinks = followLinks(options); return getFileAttributeViewImpl(file, type, followLinks); } @@ -336,7 +350,11 @@ class UnixSecureDirectoryStream private void checkWriteAccess() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ds.directory().resolve(file).checkWrite(); + if (file == null) { + ds.directory().checkWrite(); + } else { + ds.directory().resolve(file).checkWrite(); + } } } diff --git a/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java b/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java index 9d0beb50a13af5f2b83b7d30be220fa19bae3e00..8c846c1c219580fd92767af983da0d31294e8290 100644 --- a/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java +++ b/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java @@ -42,12 +42,12 @@ public class RegistryFileTypeDetector } @Override - public String implProbeContentType(FileRef file) throws IOException { + public String implProbeContentType(Path file) throws IOException { if (!(file instanceof Path)) return null; // get file extension - Path name = ((Path)file).getName(); + Path name = file.getFileName(); if (name == null) return null; String filename = name.toString(); diff --git a/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java b/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java index 20beff15474d00050547a39f6b8a653974e1e215..8a81b87a0abdfa9c8b0236b4ae6021057944155e 100644 --- a/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java +++ b/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java @@ -166,22 +166,6 @@ class WindowsFileAttributeViews { return "dos"; } - @Override - public Object getAttribute(String attribute) throws IOException { - if (attribute.equals(READONLY_NAME)) - return readAttributes().isReadOnly(); - if (attribute.equals(ARCHIVE_NAME)) - return readAttributes().isArchive(); - if (attribute.equals(SYSTEM_NAME)) - return readAttributes().isSystem(); - if (attribute.equals(HIDDEN_NAME)) - return readAttributes().isHidden(); - // implementation specific - if (attribute.equals(ATTRIBUTES_NAME)) - return readAttributes().attributes(); - return super.getAttribute(attribute); - } - @Override public void setAttribute(String attribute, Object value) throws IOException @@ -206,7 +190,7 @@ class WindowsFileAttributeViews { } @Override - public Map readAttributes(String[] attributes) + public Map readAttributes(String[] attributes) throws IOException { AttributesBuilder builder = AttributesBuilder.create(attributes); diff --git a/src/windows/classes/sun/nio/fs/WindowsFileCopy.java b/src/windows/classes/sun/nio/fs/WindowsFileCopy.java index d35752b8ee12b74e117c922be599980d0d1fe281..ed3421fb90e524e381684bd855fd9a0a270c5e04 100644 --- a/src/windows/classes/sun/nio/fs/WindowsFileCopy.java +++ b/src/windows/classes/sun/nio/fs/WindowsFileCopy.java @@ -158,7 +158,7 @@ class WindowsFileCopy { if (x.lastError() == ERROR_DIR_NOT_EMPTY || x.lastError() == ERROR_ALREADY_EXISTS) { - throw new FileAlreadyExistsException( + throw new DirectoryNotEmptyException( target.getPathForExceptionMessage()); } } @@ -369,7 +369,7 @@ class WindowsFileCopy { if (x.lastError() == ERROR_DIR_NOT_EMPTY || x.lastError() == ERROR_ALREADY_EXISTS) { - throw new FileAlreadyExistsException( + throw new DirectoryNotEmptyException( target.getPathForExceptionMessage()); } } diff --git a/src/windows/classes/sun/nio/fs/WindowsFileStore.java b/src/windows/classes/sun/nio/fs/WindowsFileStore.java index 30446bb4ae9661d90a5429b3576240d64f9ad2f0..8b3c2fb4b19af4e4cb8268b0bbd76d82868ae8f9 100644 --- a/src/windows/classes/sun/nio/fs/WindowsFileStore.java +++ b/src/windows/classes/sun/nio/fs/WindowsFileStore.java @@ -117,28 +117,47 @@ class WindowsFileStore return ((volInfo.flags() & FILE_READ_ONLY_VOLUME) != 0); } + // read the free space info + private DiskFreeSpace readDiskFreeSpace() throws IOException { + try { + return GetDiskFreeSpaceEx(root); + } catch (WindowsException x) { + x.rethrowAsIOException(root); + return null; + } + } + + @Override + public long getTotalSpace() throws IOException { + return readDiskFreeSpace().totalNumberOfBytes(); + } + + @Override + public long getUsableSpace() throws IOException { + return readDiskFreeSpace().freeBytesAvailable(); + } + + @Override + public long getUnallocatedSpace() throws IOException { + return readDiskFreeSpace().freeBytesAvailable(); + } + @Override - @SuppressWarnings("unchecked") public V getFileStoreAttributeView(Class type) { if (type == null) throw new NullPointerException(); - if (type == FileStoreSpaceAttributeView.class) - return (V) new WindowsFileStoreAttributeView(this); return (V) null; } @Override public Object getAttribute(String attribute) throws IOException { // standard - if (attribute.equals("space:totalSpace")) - return new WindowsFileStoreAttributeView(this) - .readAttributes().totalSpace(); - if (attribute.equals("space:usableSpace")) - return new WindowsFileStoreAttributeView(this) - .readAttributes().usableSpace(); - if (attribute.equals("space:unallocatedSpace")) - return new WindowsFileStoreAttributeView(this) - .readAttributes().unallocatedSpace(); + if (attribute.equals("totalSpace")) + return getTotalSpace(); + if (attribute.equals("usableSpace")) + return getUsableSpace(); + if (attribute.equals("unallocatedSpace")) + return getUnallocatedSpace(); // windows specific for testing purposes if (attribute.equals("volume:vsn")) return volInfo.volumeSerialNumber(); @@ -202,48 +221,4 @@ class WindowsFileStore sb.append(")"); return sb.toString(); } - - static class WindowsFileStoreAttributeView - implements FileStoreSpaceAttributeView - { - private final WindowsFileStore fs; - - WindowsFileStoreAttributeView(WindowsFileStore fs) { - this.fs = fs; - } - - @Override - public String name() { - return "space"; - } - - @Override - public FileStoreSpaceAttributes readAttributes() - throws IOException - { - // read the free space info - DiskFreeSpace info = null; - try { - info = GetDiskFreeSpaceEx(fs.root); - } catch (WindowsException x) { - x.rethrowAsIOException(fs.root); - } - - final DiskFreeSpace result = info; - return new FileStoreSpaceAttributes() { - @Override - public long totalSpace() { - return result.totalNumberOfBytes(); - } - @Override - public long usableSpace() { - return result.freeBytesAvailable(); - } - @Override - public long unallocatedSpace() { - return result.totalNumberOfFreeBytes(); - } - }; - } - } } diff --git a/src/windows/classes/sun/nio/fs/WindowsFileSystem.java b/src/windows/classes/sun/nio/fs/WindowsFileSystem.java index a543623ee4adb84cbd21d71c683c948551063b5c..59891ec51d5bdf3ee2d202c66625046ee6f03db0 100644 --- a/src/windows/classes/sun/nio/fs/WindowsFileSystem.java +++ b/src/windows/classes/sun/nio/fs/WindowsFileSystem.java @@ -127,7 +127,7 @@ class WindowsFileSystem } // iterate over roots, ignoring those that the security manager denies - ArrayList result = new ArrayList(); + ArrayList result = new ArrayList<>(); SecurityManager sm = System.getSecurityManager(); for (int i = 0; i <= 25; i++) { // 0->A, 1->B, 2->C... if ((drives & (1 << i)) != 0) { @@ -235,33 +235,50 @@ class WindowsFileSystem } @Override - public Path getPath(String path) { + public final Path getPath(String first, String... more) { + String path; + if (more.length == 0) { + path = first; + } else { + StringBuilder sb = new StringBuilder(); + sb.append(first); + for (String segment: more) { + if (segment.length() > 0) { + if (sb.length() > 0) + sb.append('\\'); + sb.append(segment); + } + } + path = sb.toString(); + } return WindowsPath.parse(this, path); } @Override public UserPrincipalLookupService getUserPrincipalLookupService() { - return theLookupService; + return LookupService.instance; } - private static final UserPrincipalLookupService theLookupService = - new UserPrincipalLookupService() { - @Override - public UserPrincipal lookupPrincipalByName(String name) - throws IOException - { - return WindowsUserPrincipals.lookup(name); - } - @Override - public GroupPrincipal lookupPrincipalByGroupName(String group) - throws IOException - { - UserPrincipal user = WindowsUserPrincipals.lookup(group); - if (!(user instanceof GroupPrincipal)) - throw new UserPrincipalNotFoundException(group); - return (GroupPrincipal)user; - } - }; + private static class LookupService { + static final UserPrincipalLookupService instance = + new UserPrincipalLookupService() { + @Override + public UserPrincipal lookupPrincipalByName(String name) + throws IOException + { + return WindowsUserPrincipals.lookup(name); + } + @Override + public GroupPrincipal lookupPrincipalByGroupName(String group) + throws IOException + { + UserPrincipal user = WindowsUserPrincipals.lookup(group); + if (!(user instanceof GroupPrincipal)) + throw new UserPrincipalNotFoundException(group); + return (GroupPrincipal)user; + } + }; + } @Override public PathMatcher getPathMatcher(String syntaxAndInput) { diff --git a/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java index 81193d25b9ab428afb515ac2c412e3b2e472d395..6d6a4db89b2286c38b0db6df09d1db8811b2c007 100644 --- a/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java +++ b/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java @@ -26,19 +26,25 @@ package sun.nio.fs; import java.nio.file.*; -import java.nio.file.spi.*; import java.nio.file.attribute.*; import java.nio.channels.*; import java.net.URI; import java.util.concurrent.ExecutorService; -import java.io.IOException; +import java.io.*; import java.util.*; - +import java.security.AccessController; +import sun.misc.Unsafe; import sun.nio.ch.ThreadPool; +import sun.security.util.SecurityConstants; + +import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsConstants.*; public class WindowsFileSystemProvider - extends FileSystemProvider + extends AbstractFileSystemProvider { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final String USER_DIR = "user.dir"; private final WindowsFileSystem theFileSystem; @@ -143,4 +149,505 @@ public class WindowsFileSystemProvider sd.release(); } } + + private boolean followLinks(LinkOption... options) { + boolean followLinks = true; + for (LinkOption option: options) { + if (option == LinkOption.NOFOLLOW_LINKS) { + followLinks = false; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new AssertionError("Should not get here"); + } + return followLinks; + } + + @Override + @SuppressWarnings("unchecked") + public V + getFileAttributeView(Path obj, Class view, LinkOption... options) + { + WindowsPath file = WindowsPath.toWindowsPath(obj); + if (view == null) + throw new NullPointerException(); + boolean followLinks = followLinks(options); + if (view == BasicFileAttributeView.class) + return (V) WindowsFileAttributeViews.createBasicView(file, followLinks); + if (view == DosFileAttributeView.class) + return (V) WindowsFileAttributeViews.createDosView(file, followLinks); + if (view == AclFileAttributeView.class) + return (V) new WindowsAclFileAttributeView(file, followLinks); + if (view == FileOwnerAttributeView.class) + return (V) new FileOwnerAttributeViewImpl( + new WindowsAclFileAttributeView(file, followLinks)); + if (view == UserDefinedFileAttributeView.class) + return (V) new WindowsUserDefinedFileAttributeView(file, followLinks); + return (V) null; + } + + @Override + @SuppressWarnings("unchecked") + public A readAttributes(Path file, + Class type, + LinkOption... options) + throws IOException + { + Class view; + if (type == BasicFileAttributes.class) + view = BasicFileAttributeView.class; + else if (type == DosFileAttributes.class) + view = DosFileAttributeView.class; + else if (type == null) + throw new NullPointerException(); + else + throw new UnsupportedOperationException(); + return (A) getFileAttributeView(file, view, options).readAttributes(); + } + + @Override + public DynamicFileAttributeView getFileAttributeView(Path obj, String name, LinkOption... options) { + WindowsPath file = WindowsPath.toWindowsPath(obj); + boolean followLinks = followLinks(options); + if (name.equals("basic")) + return WindowsFileAttributeViews.createBasicView(file, followLinks); + if (name.equals("dos")) + return WindowsFileAttributeViews.createDosView(file, followLinks); + if (name.equals("acl")) + return new WindowsAclFileAttributeView(file, followLinks); + if (name.equals("owner")) + return new FileOwnerAttributeViewImpl( + new WindowsAclFileAttributeView(file, followLinks)); + if (name.equals("user")) + return new WindowsUserDefinedFileAttributeView(file, followLinks); + return null; + } + + @Override + public SeekableByteChannel newByteChannel(Path obj, + Set options, + FileAttribute... attrs) + throws IOException + { + WindowsPath file = WindowsPath.toWindowsPath(obj); + WindowsSecurityDescriptor sd = + WindowsSecurityDescriptor.fromAttribute(attrs); + try { + return WindowsChannelFactory + .newFileChannel(file.getPathForWin32Calls(), + file.getPathForPermissionCheck(), + options, + sd.address()); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + return null; // keep compiler happy + } finally { + sd.release(); + } + } + + @Override + boolean implDelete(Path obj, boolean failIfNotExists) throws IOException { + WindowsPath file = WindowsPath.toWindowsPath(obj); + file.checkDelete(); + + WindowsFileAttributes attrs = null; + try { + // need to know if file is a directory or junction + attrs = WindowsFileAttributes.get(file, false); + if (attrs.isDirectory() || attrs.isDirectoryLink()) { + RemoveDirectory(file.getPathForWin32Calls()); + } else { + DeleteFile(file.getPathForWin32Calls()); + } + return true; + } catch (WindowsException x) { + + // no-op if file does not exist + if (!failIfNotExists && + (x.lastError() == ERROR_FILE_NOT_FOUND || + x.lastError() == ERROR_PATH_NOT_FOUND)) return false; + + if (attrs != null && attrs.isDirectory()) { + // ERROR_ALREADY_EXISTS is returned when attempting to delete + // non-empty directory on SAMBA servers. + if (x.lastError() == ERROR_DIR_NOT_EMPTY || + x.lastError() == ERROR_ALREADY_EXISTS) + { + throw new DirectoryNotEmptyException( + file.getPathForExceptionMessage()); + } + } + x.rethrowAsIOException(file); + return false; + } + } + + @Override + public void copy(Path source, Path target, CopyOption... options) + throws IOException + { + WindowsFileCopy.copy(WindowsPath.toWindowsPath(source), + WindowsPath.toWindowsPath(target), + options); + } + + @Override + public void move(Path source, Path target, CopyOption... options) + throws IOException + { + WindowsFileCopy.move(WindowsPath.toWindowsPath(source), + WindowsPath.toWindowsPath(target), + options); + } + + /** + * Returns buffer with SID_AND_ATTRIBUTES structure representing the user + * associated with the current thread access token. + * FIXME - this should be cached. + */ + private static NativeBuffer getUserInfo(WindowsPath file) throws IOException { + try { + long hToken = WindowsSecurity.processTokenWithQueryAccess; + int size = GetTokenInformation(hToken, TokenUser, 0L, 0); + assert size > 0; + + NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); + try { + int newsize = GetTokenInformation(hToken, TokenUser, + buffer.address(), size); + if (newsize != size) + throw new AssertionError(); + return buffer; + } catch (WindowsException x) { + buffer.release(); + throw x; + } + } catch (WindowsException x) { + throw new IOException(x.getMessage()); + } + } + + /** + * Reads the file ACL and return the effective access as ACCESS_MASK + */ + private static int getEffectiveAccess(WindowsPath file) throws IOException { + // read security descriptor continaing ACL (symlinks are followed) + String target = WindowsLinkSupport.getFinalPath(file, true); + NativeBuffer aclBuffer = WindowsAclFileAttributeView + .getFileSecurity(target, DACL_SECURITY_INFORMATION); + + // retrieves DACL from security descriptor + long pAcl = GetSecurityDescriptorDacl(aclBuffer.address()); + + // Use GetEffectiveRightsFromAcl to get effective access to file + try { + NativeBuffer userBuffer = getUserInfo(file); + try { + try { + // SID_AND_ATTRIBUTES->pSid + long pSid = unsafe.getAddress(userBuffer.address()); + long pTrustee = BuildTrusteeWithSid(pSid); + try { + return GetEffectiveRightsFromAcl(pAcl, pTrustee); + } finally { + LocalFree(pTrustee); + } + } catch (WindowsException x) { + throw new IOException("Unable to get effective rights from ACL: " + + x.getMessage()); + } + } finally { + userBuffer.release(); + } + } finally { + aclBuffer.release(); + } + } + + @Override + public void checkAccess(Path obj, AccessMode... modes) throws IOException { + WindowsPath file = WindowsPath.toWindowsPath(obj); + // if no access modes then simply file attributes + if (modes.length == 0) { + file.checkRead(); + try { + WindowsFileAttributes.get(file, true); + } catch (WindowsException exc) { + exc.rethrowAsIOException(file); + } + return; + } + + boolean r = false; + boolean w = false; + boolean x = false; + for (AccessMode mode: modes) { + switch (mode) { + case READ : r = true; break; + case WRITE : w = true; break; + case EXECUTE : x = true; break; + default: throw new AssertionError("Should not get here"); + } + } + + int mask = 0; + if (r) { + file.checkRead(); + mask |= FILE_READ_DATA; + } + if (w) { + file.checkWrite(); + mask |= FILE_WRITE_DATA; + } + if (x) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkExec(file.getPathForPermissionCheck()); + mask |= FILE_EXECUTE; + } + + if ((getEffectiveAccess(file) & mask) == 0) + throw new AccessDeniedException( + file.getPathForExceptionMessage(), null, + "Effective permissions does not allow requested access"); + + // for write access we neeed to check if the DOS readonly attribute + // and if the volume is read-only + if (w) { + try { + WindowsFileAttributes attrs = WindowsFileAttributes.get(file, true); + if (!attrs.isDirectory() && attrs.isReadOnly()) + throw new AccessDeniedException( + file.getPathForExceptionMessage(), null, + "DOS readonly attribute is set"); + } catch (WindowsException exc) { + exc.rethrowAsIOException(file); + } + + if (WindowsFileStore.create(file).isReadOnly()) { + throw new AccessDeniedException( + file.getPathForExceptionMessage(), null, "Read-only file system"); + } + return; + } + } + + @Override + public boolean isSameFile(Path obj1, Path obj2) throws IOException { + WindowsPath file1 = WindowsPath.toWindowsPath(obj1); + if (file1.equals(obj2)) + return true; + if (obj2 == null) + throw new NullPointerException(); + if (!(obj2 instanceof WindowsPath)) + return false; + WindowsPath file2 = (WindowsPath)obj2; + + // check security manager access to both files + file1.checkRead(); + file2.checkRead(); + + // open both files and see if they are the same + long h1 = 0L; + try { + h1 = file1.openForReadAttributeAccess(true); + } catch (WindowsException x) { + x.rethrowAsIOException(file1); + } + try { + WindowsFileAttributes attrs1 = null; + try { + attrs1 = WindowsFileAttributes.readAttributes(h1); + } catch (WindowsException x) { + x.rethrowAsIOException(file1); + } + long h2 = 0L; + try { + h2 = file2.openForReadAttributeAccess(true); + } catch (WindowsException x) { + x.rethrowAsIOException(file2); + } + try { + WindowsFileAttributes attrs2 = null; + try { + attrs2 = WindowsFileAttributes.readAttributes(h2); + } catch (WindowsException x) { + x.rethrowAsIOException(file2); + } + return WindowsFileAttributes.isSameFile(attrs1, attrs2); + } finally { + CloseHandle(h2); + } + } finally { + CloseHandle(h1); + } + } + + @Override + public boolean isHidden(Path obj) throws IOException { + WindowsPath file = WindowsPath.toWindowsPath(obj); + file.checkRead(); + WindowsFileAttributes attrs = null; + try { + attrs = WindowsFileAttributes.get(file, true); + } catch (WindowsException x) { + x.rethrowAsIOException(file); + } + // DOS hidden attribute not meaningful when set on directories + if (attrs.isDirectory()) + return false; + return attrs.isHidden(); + } + + @Override + public FileStore getFileStore(Path obj) throws IOException { + WindowsPath file = WindowsPath.toWindowsPath(obj); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); + file.checkRead(); + } + return WindowsFileStore.create(file); + } + + + @Override + public void createDirectory(Path obj, FileAttribute... attrs) + throws IOException + { + WindowsPath dir = WindowsPath.toWindowsPath(obj); + dir.checkWrite(); + WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs); + try { + CreateDirectory(dir.getPathForWin32Calls(), sd.address()); + } catch (WindowsException x) { + x.rethrowAsIOException(dir); + } finally { + sd.release(); + } + } + + @Override + public DirectoryStream newDirectoryStream(Path obj, DirectoryStream.Filter filter) + throws IOException + { + WindowsPath dir = WindowsPath.toWindowsPath(obj); + dir.checkRead(); + if (filter == null) + throw new NullPointerException(); + return new WindowsDirectoryStream(dir, filter); + } + + @Override + public void createSymbolicLink(Path obj1, Path obj2, FileAttribute... attrs) + throws IOException + { + WindowsPath link = WindowsPath.toWindowsPath(obj1); + WindowsPath target = WindowsPath.toWindowsPath(obj2); + + if (!link.getFileSystem().supportsLinks()) { + throw new UnsupportedOperationException("Symbolic links not supported " + + "on this operating system"); + } + + // no attributes allowed + if (attrs.length > 0) { + WindowsSecurityDescriptor.fromAttribute(attrs); // may throw NPE or UOE + throw new UnsupportedOperationException("Initial file attributes" + + "not supported when creating symbolic link"); + } + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LinkPermission("symbolic")); + link.checkWrite(); + } + + /** + * Throw I/O exception for the drive-relative case because Windows + * creates a link with the resolved target for this case. + */ + if (target.type() == WindowsPathType.DRIVE_RELATIVE) { + throw new IOException("Cannot create symbolic link to working directory relative target"); + } + + /* + * Windows treates symbolic links to directories differently than it + * does to other file types. For that reason we need to check if the + * target is a directory (or a directory junction). + */ + WindowsPath resolvedTarget; + if (target.type() == WindowsPathType.RELATIVE) { + WindowsPath parent = link.getParent(); + resolvedTarget = (parent == null) ? target : parent.resolve(target); + } else { + resolvedTarget = link.resolve(target); + } + int flags = 0; + try { + WindowsFileAttributes wattrs = WindowsFileAttributes.get(resolvedTarget, false); + if (wattrs.isDirectory() || wattrs.isDirectoryLink()) + flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; + } catch (WindowsException x) { + // unable to access target so assume target is not a directory + } + + // create the link + try { + CreateSymbolicLink(link.getPathForWin32Calls(), + WindowsPath.addPrefixIfNeeded(target.toString()), + flags); + } catch (WindowsException x) { + if (x.lastError() == ERROR_INVALID_REPARSE_DATA) { + x.rethrowAsIOException(link, target); + } else { + x.rethrowAsIOException(link); + } + } + } + + @Override + public void createLink(Path obj1, Path obj2) throws IOException { + WindowsPath link = WindowsPath.toWindowsPath(obj1); + WindowsPath existing = WindowsPath.toWindowsPath(obj2); + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LinkPermission("hard")); + link.checkWrite(); + existing.checkWrite(); + } + + // create hard link + try { + CreateHardLink(link.getPathForWin32Calls(), + existing.getPathForWin32Calls()); + } catch (WindowsException x) { + x.rethrowAsIOException(link, existing); + } + } + + @Override + public Path readSymbolicLink(Path obj1) throws IOException { + WindowsPath link = WindowsPath.toWindowsPath(obj1); + WindowsFileSystem fs = link.getFileSystem(); + if (!fs.supportsLinks()) { + throw new UnsupportedOperationException("symbolic links not supported"); + } + + // permission check + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + FilePermission perm = new FilePermission(link.getPathForPermissionCheck(), + SecurityConstants.FILE_READLINK_ACTION); + AccessController.checkPermission(perm); + } + + String target = WindowsLinkSupport.readLink(link); + return WindowsPath.createFromNormalizedPath(fs, target); + } } diff --git a/src/windows/classes/sun/nio/fs/WindowsPath.java b/src/windows/classes/sun/nio/fs/WindowsPath.java index 3e79ab43ab60227436badca15f8ef1f454796503..26c2b26ce8e6c08200f587c520a0497137275115 100644 --- a/src/windows/classes/sun/nio/fs/WindowsPath.java +++ b/src/windows/classes/sun/nio/fs/WindowsPath.java @@ -27,18 +27,13 @@ package sun.nio.fs; import java.nio.file.*; import java.nio.file.attribute.*; -import java.nio.channels.*; import java.io.*; import java.net.URI; -import java.security.AccessController; import java.util.*; import java.lang.ref.WeakReference; import com.sun.nio.file.ExtendedWatchEventModifier; -import sun.security.util.SecurityConstants; -import sun.misc.Unsafe; - import static sun.nio.fs.WindowsNativeDispatcher.*; import static sun.nio.fs.WindowsConstants.*; @@ -47,7 +42,6 @@ import static sun.nio.fs.WindowsConstants.*; */ class WindowsPath extends AbstractPath { - private static final Unsafe unsafe = Unsafe.getUnsafe(); // The maximum path that does not require long path prefix. On Windows // the maximum path is 260 minus 1 (NUL) but for directories it is 260 @@ -229,6 +223,8 @@ class WindowsPath extends AbstractPath { // Relative path ("foo" for example) if (type == WindowsPathType.RELATIVE) { String defaultDirectory = getFileSystem().defaultDirectory(); + if (isEmpty()) + return defaultDirectory; if (defaultDirectory.endsWith("\\")) { return defaultDirectory + path; } else { @@ -286,7 +282,7 @@ class WindowsPath extends AbstractPath { } // Add long path prefix to path if required - private static String addPrefixIfNeeded(String path) { + static String addPrefixIfNeeded(String path) { if (path.length() > 248) { if (path.startsWith("\\\\")) { path = "\\\\?\\UNC" + path.substring(1, path.length()); @@ -304,10 +300,22 @@ class WindowsPath extends AbstractPath { // -- Path operations -- + private boolean isEmpty() { + return path.length() == 0; + } + + private WindowsPath emptyPath() { + return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", ""); + } + @Override - public Path getName() { + public Path getFileName() { + int len = path.length(); + // represents empty path + if (len == 0) + return this; // represents root component only - if (root.length() == path.length()) + if (root.length() == len) return null; int off = path.lastIndexOf('\\'); if (off < root.length()) @@ -339,6 +347,11 @@ class WindowsPath extends AbstractPath { return new WindowsPath(getFileSystem(), type, root, root); } + // package-private + WindowsPathType type() { + return type; + } + // package-private boolean isUnc() { return type == WindowsPathType.UNC; @@ -355,7 +368,7 @@ class WindowsPath extends AbstractPath { return type == WindowsPathType.ABSOLUTE || type == WindowsPathType.UNC; } - private WindowsPath checkPath(FileRef path) { + static WindowsPath toWindowsPath(Path path) { if (path == null) throw new NullPointerException(); if (!(path instanceof WindowsPath)) { @@ -366,9 +379,9 @@ class WindowsPath extends AbstractPath { @Override public WindowsPath relativize(Path obj) { - WindowsPath other = checkPath(obj); + WindowsPath other = toWindowsPath(obj); if (this.equals(other)) - return null; + return emptyPath(); // can only relativize paths of the same type if (this.type != other.type) @@ -410,7 +423,7 @@ class WindowsPath extends AbstractPath { @Override public Path normalize() { final int count = getNameCount(); - if (count == 0) + if (count == 0 || isEmpty()) return this; boolean[] ignore = new boolean[count]; // true => ignore name @@ -488,7 +501,7 @@ class WindowsPath extends AbstractPath { // corner case - all names removed if (remaining == 0) { - return getRoot(); + return (root.length() == 0) ? emptyPath() : getRoot(); } // re-constitute the path from the remaining names. @@ -497,7 +510,7 @@ class WindowsPath extends AbstractPath { result.append(root); for (int i=0; i list = new ArrayList(); - int start = root.length(); - int off = root.length(); - while (off < path.length()) { - if (path.charAt(off) != '\\') { - off++; - } else { - list.add(start); - start = ++off; + ArrayList list = new ArrayList<>(); + if (isEmpty()) { + // empty path considered to have one name element + list.add(0); + } else { + int start = root.length(); + int off = root.length(); + while (off < path.length()) { + if (path.charAt(off) != '\\') { + off++; + } else { + list.add(start); + start = ++off; + } } + if (start != off) + list.add(start); } - if (start != off) - list.add(start); synchronized (this) { if (offsets == null) offsets = list.toArray(new Integer[list.size()]); @@ -633,11 +646,16 @@ class WindowsPath extends AbstractPath { @Override public boolean startsWith(Path obj) { - WindowsPath other = checkPath(obj); + WindowsPath other = toWindowsPath(obj); // if this path has a root component the given path's root must match - if (!this.root.equalsIgnoreCase(other.root)) + if (!this.root.equalsIgnoreCase(other.root)) { return false; + } + + // empty path starts with itself + if (other.isEmpty()) + return this.isEmpty(); // roots match so compare elements int thisCount = getNameCount(); @@ -657,13 +675,18 @@ class WindowsPath extends AbstractPath { @Override public boolean endsWith(Path obj) { - WindowsPath other = checkPath(obj); + WindowsPath other = toWindowsPath(obj); // other path is longer - if (other.path.length() > path.length()) { + if (other.path.length() > this.path.length()) { return false; } + // empty path ends in itself + if (other.isEmpty()) { + return this.isEmpty(); + } + int thisCount = this.getNameCount(); int otherCount = other.getNameCount(); @@ -742,31 +765,6 @@ class WindowsPath extends AbstractPath { return path; } - @Override - public Iterator iterator() { - return new Iterator() { - private int i = 0; - @Override - public boolean hasNext() { - return (i < getNameCount()); - } - @Override - public Path next() { - if (i < getNameCount()) { - Path result = getName(i); - i++; - return result; - } else { - throw new NoSuchElementException(); - } - } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - // -- file operations -- // package-private @@ -805,453 +803,6 @@ class WindowsPath extends AbstractPath { } } - @Override - public FileStore getFileStore() - throws IOException - { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); - checkRead(); - } - return WindowsFileStore.create(this); - } - - /** - * Returns buffer with SID_AND_ATTRIBUTES structure representing the user - * associated with the current thread access token. - * FIXME - this should be cached. - */ - private NativeBuffer getUserInfo() throws IOException { - try { - long hToken = WindowsSecurity.processTokenWithQueryAccess; - int size = GetTokenInformation(hToken, TokenUser, 0L, 0); - assert size > 0; - - NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); - try { - int newsize = GetTokenInformation(hToken, TokenUser, - buffer.address(), size); - if (newsize != size) - throw new AssertionError(); - return buffer; - } catch (WindowsException x) { - buffer.release(); - throw x; - } - } catch (WindowsException x) { - throw new IOException(x.getMessage()); - } - } - - /** - * Reads the file ACL and return the effective access as ACCESS_MASK - */ - private int getEffectiveAccess() throws IOException { - // read security descriptor continaing ACL (symlinks are followed) - String target = WindowsLinkSupport.getFinalPath(this, true); - NativeBuffer aclBuffer = WindowsAclFileAttributeView - .getFileSecurity(target, DACL_SECURITY_INFORMATION); - - // retrieves DACL from security descriptor - long pAcl = GetSecurityDescriptorDacl(aclBuffer.address()); - - // Use GetEffectiveRightsFromAcl to get effective access to file - try { - NativeBuffer userBuffer = getUserInfo(); - try { - try { - // SID_AND_ATTRIBUTES->pSid - long pSid = unsafe.getAddress(userBuffer.address()); - long pTrustee = BuildTrusteeWithSid(pSid); - try { - return GetEffectiveRightsFromAcl(pAcl, pTrustee); - } finally { - LocalFree(pTrustee); - } - } catch (WindowsException x) { - throw new IOException("Unable to get effective rights from ACL: " + - x.getMessage()); - } - } finally { - userBuffer.release(); - } - } finally { - aclBuffer.release(); - } - } - - @Override - public void checkAccess(AccessMode... modes) throws IOException { - // if no access modes then simply file attributes - if (modes.length == 0) { - checkRead(); - try { - WindowsFileAttributes.get(this, true); - } catch (WindowsException exc) { - exc.rethrowAsIOException(this); - } - return; - } - - boolean r = false; - boolean w = false; - boolean x = false; - for (AccessMode mode: modes) { - switch (mode) { - case READ : r = true; break; - case WRITE : w = true; break; - case EXECUTE : x = true; break; - default: throw new AssertionError("Should not get here"); - } - } - - int mask = 0; - if (r) { - checkRead(); - mask |= FILE_READ_DATA; - } - if (w) { - checkWrite(); - mask |= FILE_WRITE_DATA; - } - if (x) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkExec(getPathForPermissionCheck()); - mask |= FILE_EXECUTE; - } - - if ((getEffectiveAccess() & mask) == 0) - throw new AccessDeniedException( - this.getPathForExceptionMessage(), null, - "Effective permissions does not allow requested access"); - - // for write access we neeed to check if the DOS readonly attribute - // and if the volume is read-only - if (w) { - try { - WindowsFileAttributes attrs = WindowsFileAttributes.get(this, true); - if (!attrs.isDirectory() && attrs.isReadOnly()) - throw new AccessDeniedException( - this.getPathForExceptionMessage(), null, - "DOS readonly attribute is set"); - } catch (WindowsException exc) { - exc.rethrowAsIOException(this); - } - - if (WindowsFileStore.create(this).isReadOnly()) { - throw new AccessDeniedException( - this.getPathForExceptionMessage(), null, "Read-only file system"); - } - return; - } - } - - @Override - void implDelete(boolean failIfNotExists) throws IOException { - checkDelete(); - - WindowsFileAttributes attrs = null; - try { - // need to know if file is a directory or junction - attrs = WindowsFileAttributes.get(this, false); - if (attrs.isDirectory() || attrs.isDirectoryLink()) { - RemoveDirectory(getPathForWin32Calls()); - } else { - DeleteFile(getPathForWin32Calls()); - } - } catch (WindowsException x) { - - // no-op if file does not exist - if (!failIfNotExists && - (x.lastError() == ERROR_FILE_NOT_FOUND || - x.lastError() == ERROR_PATH_NOT_FOUND)) return; - - if (attrs != null && attrs.isDirectory()) { - // ERROR_ALREADY_EXISTS is returned when attempting to delete - // non-empty directory on SAMBA servers. - if (x.lastError() == ERROR_DIR_NOT_EMPTY || - x.lastError() == ERROR_ALREADY_EXISTS) - { - throw new DirectoryNotEmptyException( - getPathForExceptionMessage()); - } - } - x.rethrowAsIOException(this); - } - } - - @Override - public DirectoryStream newDirectoryStream(DirectoryStream.Filter filter) - throws IOException - { - checkRead(); - if (filter == null) - throw new NullPointerException(); - return new WindowsDirectoryStream(this, filter); - } - - @Override - public void implCopyTo(Path obj, CopyOption... options) throws IOException { - WindowsPath target = (WindowsPath)obj; - WindowsFileCopy.copy(this, target, options); - } - - @Override - public void implMoveTo(Path obj, CopyOption... options) throws IOException { - WindowsPath target = (WindowsPath)obj; - WindowsFileCopy.move(this, target, options); - } - - private boolean followLinks(LinkOption... options) { - boolean followLinks = true; - for (LinkOption option: options) { - if (option == LinkOption.NOFOLLOW_LINKS) { - followLinks = false; - continue; - } - if (option == null) - throw new NullPointerException(); - throw new AssertionError("Should not get here"); - } - return followLinks; - } - - @Override - @SuppressWarnings("unchecked") - public V - getFileAttributeView(Class view, LinkOption... options) - { - if (view == null) - throw new NullPointerException(); - boolean followLinks = followLinks(options); - if (view == BasicFileAttributeView.class) - return (V) WindowsFileAttributeViews.createBasicView(this, followLinks); - if (view == DosFileAttributeView.class) - return (V) WindowsFileAttributeViews.createDosView(this, followLinks); - if (view == AclFileAttributeView.class) - return (V) new WindowsAclFileAttributeView(this, followLinks); - if (view == FileOwnerAttributeView.class) - return (V) new FileOwnerAttributeViewImpl( - new WindowsAclFileAttributeView(this, followLinks)); - if (view == UserDefinedFileAttributeView.class) - return (V) new WindowsUserDefinedFileAttributeView(this, followLinks); - return (V) null; - } - - @Override - public DynamicFileAttributeView getFileAttributeView(String name, LinkOption... options) { - boolean followLinks = followLinks(options); - if (name.equals("basic")) - return WindowsFileAttributeViews.createBasicView(this, followLinks); - if (name.equals("dos")) - return WindowsFileAttributeViews.createDosView(this, followLinks); - if (name.equals("acl")) - return new WindowsAclFileAttributeView(this, followLinks); - if (name.equals("owner")) - return new FileOwnerAttributeViewImpl( - new WindowsAclFileAttributeView(this, followLinks)); - if (name.equals("user")) - return new WindowsUserDefinedFileAttributeView(this, followLinks); - return null; - } - - @Override - public WindowsPath createDirectory(FileAttribute... attrs) - throws IOException - { - checkWrite(); - WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs); - try { - CreateDirectory(getPathForWin32Calls(), sd.address()); - } catch (WindowsException x) { - x.rethrowAsIOException(this); - } finally { - sd.release(); - } - return this; - } - - @Override - public SeekableByteChannel newByteChannel(Set options, - FileAttribute... attrs) - throws IOException - { - WindowsSecurityDescriptor sd = - WindowsSecurityDescriptor.fromAttribute(attrs); - try { - return WindowsChannelFactory - .newFileChannel(getPathForWin32Calls(), - getPathForPermissionCheck(), - options, - sd.address()); - } catch (WindowsException x) { - x.rethrowAsIOException(this); - return null; // keep compiler happy - } finally { - sd.release(); - } - } - - @Override - public boolean isSameFile(Path obj) throws IOException { - if (this.equals(obj)) - return true; - if (!(obj instanceof WindowsPath)) // includes null check - return false; - WindowsPath other = (WindowsPath)obj; - - // check security manager access to both files - this.checkRead(); - other.checkRead(); - - // open both files and see if they are the same - long h1 = 0L; - try { - h1 = this.openForReadAttributeAccess(true); - } catch (WindowsException x) { - x.rethrowAsIOException(this); - } - try { - WindowsFileAttributes attrs1 = null; - try { - attrs1 = WindowsFileAttributes.readAttributes(h1); - } catch (WindowsException x) { - x.rethrowAsIOException(this); - } - long h2 = 0L; - try { - h2 = other.openForReadAttributeAccess(true); - } catch (WindowsException x) { - x.rethrowAsIOException(other); - } - try { - WindowsFileAttributes attrs2 = null; - try { - attrs2 = WindowsFileAttributes.readAttributes(h2); - } catch (WindowsException x) { - x.rethrowAsIOException(other); - } - return WindowsFileAttributes.isSameFile(attrs1, attrs2); - } finally { - CloseHandle(h2); - } - } finally { - CloseHandle(h1); - } - } - - @Override - public WindowsPath createSymbolicLink(Path obj, FileAttribute... attrs) - throws IOException - { - if (!getFileSystem().supportsLinks()) { - throw new UnsupportedOperationException("Symbolic links not supported " - + "on this operating system"); - } - - WindowsPath target = checkPath(obj); - - // no attributes allowed - if (attrs.length > 0) { - WindowsSecurityDescriptor.fromAttribute(attrs); // may throw NPE or UOE - throw new UnsupportedOperationException("Initial file attributes" + - "not supported when creating symbolic link"); - } - - // permission check - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new LinkPermission("symbolic")); - this.checkWrite(); - } - - /** - * Throw I/O exception for the drive-relative case because Windows - * creates a link with the resolved target for this case. - */ - if (target.type == WindowsPathType.DRIVE_RELATIVE) { - throw new IOException("Cannot create symbolic link to working directory relative target"); - } - - /* - * Windows treates symbolic links to directories differently than it - * does to other file types. For that reason we need to check if the - * target is a directory (or a directory junction). - */ - WindowsPath resolvedTarget; - if (target.type == WindowsPathType.RELATIVE) { - WindowsPath parent = getParent(); - resolvedTarget = (parent == null) ? target : parent.resolve(target); - } else { - resolvedTarget = resolve(target); - } - int flags = 0; - try { - WindowsFileAttributes wattrs = WindowsFileAttributes.get(resolvedTarget, false); - if (wattrs.isDirectory() || wattrs.isDirectoryLink()) - flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; - } catch (WindowsException x) { - // unable to access target so assume target is not a directory - } - - // create the link - try { - CreateSymbolicLink(getPathForWin32Calls(), - addPrefixIfNeeded(target.toString()), - flags); - } catch (WindowsException x) { - if (x.lastError() == ERROR_INVALID_REPARSE_DATA) { - x.rethrowAsIOException(this, target); - } else { - x.rethrowAsIOException(this); - } - } - return this; - } - - @Override - public Path createLink(Path obj) throws IOException { - WindowsPath existing = checkPath(obj); - - // permission check - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new LinkPermission("hard")); - this.checkWrite(); - existing.checkWrite(); - } - - // create hard link - try { - CreateHardLink(this.getPathForWin32Calls(), - existing.getPathForWin32Calls()); - } catch (WindowsException x) { - x.rethrowAsIOException(this, existing); - } - - return this; - } - - @Override - public WindowsPath readSymbolicLink() throws IOException { - if (!getFileSystem().supportsLinks()) { - throw new UnsupportedOperationException("symbolic links not supported"); - } - - // permission check - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - FilePermission perm = new FilePermission(getPathForPermissionCheck(), - SecurityConstants.FILE_READLINK_ACTION); - AccessController.checkPermission(perm); - } - - String target = WindowsLinkSupport.readLink(this); - return createFromNormalizedPath(getFileSystem(), target); - } - @Override public URI toUri() { return WindowsUriSupport.toUri(this); @@ -1282,21 +833,6 @@ class WindowsPath extends AbstractPath { return createFromNormalizedPath(getFileSystem(), rp); } - @Override - public boolean isHidden() throws IOException { - checkRead(); - WindowsFileAttributes attrs = null; - try { - attrs = WindowsFileAttributes.get(this, true); - } catch (WindowsException x) { - x.rethrowAsIOException(this); - } - // DOS hidden attribute not meaningful when set on directories - if (attrs.isDirectory()) - return false; - return attrs.isHidden(); - } - @Override public WatchKey register(WatchService watcher, WatchEvent.Kind[] events, diff --git a/src/windows/classes/sun/nio/fs/WindowsPathParser.java b/src/windows/classes/sun/nio/fs/WindowsPathParser.java index b985d136f71142e7304670c5fcb7163863a1d169..e898fd55fd27bbe8d65baf5faf2f0e95ba4eccbe 100644 --- a/src/windows/classes/sun/nio/fs/WindowsPathParser.java +++ b/src/windows/classes/sun/nio/fs/WindowsPathParser.java @@ -74,8 +74,6 @@ class WindowsPathParser { * Parses the given input as a Windows path */ static Result parse(String input) { - if (input == null || input.length() == 0) - throw new InvalidPathException(input, "Empty or null path"); return parse(input, true); } @@ -135,7 +133,7 @@ class WindowsPathParser { } } if (off == 0) { - if (isSlash(input.charAt(0))) { + if (len > 0 && isSlash(input.charAt(0))) { type = WindowsPathType.DIRECTORY_RELATIVE; root = "\\"; } else { diff --git a/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java b/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java index f0c458761ac1954894137834a131bdcf95098119..7d9464e0ce46bc27e56ef3ef4da62d071c90efec 100644 --- a/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java +++ b/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java @@ -214,7 +214,7 @@ class WindowsSecurityDescriptor { // map flags byte aceFlags = unsafe.getByte(aceAddress + OFFSETOF_FLAGS); - Set flags = new HashSet(); + Set flags = EnumSet.noneOf(AclEntryFlag.class); if ((aceFlags & OBJECT_INHERIT_ACE) != 0) flags.add(AclEntryFlag.FILE_INHERIT); if ((aceFlags & CONTAINER_INHERIT_ACE) != 0) @@ -226,7 +226,7 @@ class WindowsSecurityDescriptor { // map access mask int mask = unsafe.getInt(aceAddress + OFFSETOF_ACCESS_MASK); - Set perms = new HashSet(); + Set perms = EnumSet.noneOf(AclEntryPermission.class); if ((mask & FILE_READ_DATA) > 0) perms.add(AclEntryPermission.READ_DATA); if ((mask & FILE_WRITE_DATA) > 0) @@ -378,7 +378,7 @@ class WindowsSecurityDescriptor { AclInformation aclInfo = GetAclInformation(aclAddress); aceCount = aclInfo.aceCount(); } - ArrayList result = new ArrayList(aceCount); + ArrayList result = new ArrayList<>(aceCount); // decode each of the ACEs to AclEntry objects for (int i=0; i listUsingStreamEnumeration() throws IOException { - List list = new ArrayList(); + List list = new ArrayList<>(); try { FirstStream first = FindFirstStream(file.getPathForWin32Calls()); if (first != null) { @@ -114,7 +114,7 @@ class WindowsUserDefinedFileAttributeView NativeBuffer buffer = null; // result with names of alternative data streams - final List list = new ArrayList(); + final List list = new ArrayList<>(); try { buffer = NativeBuffers.getNativeBuffer(BUFFER_SIZE); @@ -216,7 +216,7 @@ class WindowsUserDefinedFileAttributeView // wrap with channel FileChannel fc = null; try { - Set opts = new HashSet(); + Set opts = new HashSet<>(); opts.add(READ); if (!followLinks) opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT); @@ -243,7 +243,7 @@ class WindowsUserDefinedFileAttributeView // wrap with channel FileChannel fc = null; try { - Set opts = new HashSet(); + Set opts = new HashSet<>(); opts.add(READ); if (!followLinks) opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT); @@ -298,7 +298,7 @@ class WindowsUserDefinedFileAttributeView x.rethrowAsIOException(file); } try { - Set opts = new HashSet(); + Set opts = new HashSet<>(); if (!followLinks) opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT); opts.add(CREATE); diff --git a/src/windows/classes/sun/nio/fs/WindowsWatchService.java b/src/windows/classes/sun/nio/fs/WindowsWatchService.java index d86673cf13490c77ea457b79da579a98fb10db44..53f2fa2af56bb49a83b599d63a77f50f70fd2304 100644 --- a/src/windows/classes/sun/nio/fs/WindowsWatchService.java +++ b/src/windows/classes/sun/nio/fs/WindowsWatchService.java @@ -106,8 +106,11 @@ class WindowsWatchService // completion key (used to map I/O completion to WatchKey) private int completionKey; - WindowsWatchKey(AbstractWatchService watcher, FileKey fileKey) { - super(watcher); + WindowsWatchKey(Path dir, + AbstractWatchService watcher, + FileKey fileKey) + { + super(dir, watcher); this.fileKey = fileKey; } @@ -405,7 +408,7 @@ class WindowsWatchService WindowsWatchKey watchKey; if (existing == null) { // not registered so create new watch key - watchKey = new WindowsWatchKey(watcher, fk) + watchKey = new WindowsWatchKey(dir, watcher, fk) .init(handle, events, watchSubtree, buffer, countAddress, overlappedAddress, completionKey); // map file key to watch key diff --git a/test/demo/zipfs/basic.sh b/test/demo/zipfs/basic.sh index c6cfb77caf385fbb622da2fff7a319d20f569abd..45d2d74ac42e122467f1e786df073d8bc9a55f6d 100644 --- a/test/demo/zipfs/basic.sh +++ b/test/demo/zipfs/basic.sh @@ -22,6 +22,7 @@ # # @test # @bug 6990846 +# @ignore Until zipfs updated (7015391) # @summary Test ZipFileSystem demo # @build Basic PathOps ZipFSTester # @run shell basic.sh diff --git a/test/java/io/File/IsHidden.java b/test/java/io/File/IsHidden.java index 9e062fe61e33e69920923257448f9d703c85946a..d2b43c5b64104fc4ae520e7b73ab5510e45eea5a 100644 --- a/test/java/io/File/IsHidden.java +++ b/test/java/io/File/IsHidden.java @@ -27,6 +27,7 @@ */ import java.io.*; +import java.nio.file.Files; import java.nio.file.attribute.DosFileAttributeView; public class IsHidden { @@ -42,7 +43,7 @@ public class IsHidden { } private static void setHidden(File f, boolean value) throws IOException { - f.toPath().getFileAttributeView(DosFileAttributeView.class).setHidden(value); + Files.getFileAttributeView(f.toPath(), DosFileAttributeView.class).setHidden(value); } private static void testWin32() throws Exception { diff --git a/test/java/io/File/SetAccess.java b/test/java/io/File/SetAccess.java index bb88ec462588d27d29b0dd33c23d292e3b9aeb59..745deab1f7b89529b5a57b4ff4199a238591ccea 100644 --- a/test/java/io/File/SetAccess.java +++ b/test/java/io/File/SetAccess.java @@ -27,6 +27,7 @@ */ import java.io.*; +import java.nio.file.*; import java.nio.file.attribute.*; public class SetAccess { @@ -178,7 +179,7 @@ public class SetAccess { } private static String permission(File f) throws Exception { - PosixFileAttributes attrs = Attributes.readPosixFileAttributes(f.toPath()); + PosixFileAttributes attrs = Files.readAttributes(f.toPath(), PosixFileAttributes.class); String type = attrs.isDirectory() ? "d" : " "; return type + PosixFilePermissions.toString(attrs.permissions()); } diff --git a/test/java/io/File/SymLinks.java b/test/java/io/File/SymLinks.java index 36306f98d7a4f2b3562d2c3922940cac913dfbd4..355b28875d465e6104fa020ede170d732f4981be 100644 --- a/test/java/io/File/SymLinks.java +++ b/test/java/io/File/SymLinks.java @@ -27,7 +27,7 @@ */ import java.io.*; -import java.nio.file.Path; +import java.nio.file.*; import java.nio.file.attribute.*; import static java.nio.file.LinkOption.*; @@ -80,39 +80,33 @@ public class SymLinks { if (file != null) file.delete(); if (link2file != null) - link2file.toPath().deleteIfExists(); + Files.deleteIfExists(link2file.toPath()); if (link2link2file != null) - link2link2file.toPath().deleteIfExists(); + Files.deleteIfExists(link2link2file.toPath()); if (dir != null) dir.delete(); if (link2dir != null) - link2dir.toPath().deleteIfExists(); + Files.deleteIfExists(link2dir.toPath()); if (link2link2dir != null) - link2link2dir.toPath().deleteIfExists(); + Files.deleteIfExists(link2link2dir.toPath()); if (link2nobody != null) - link2nobody.toPath().deleteIfExists(); + Files.deleteIfExists(link2nobody.toPath()); if (link2link2nobody != null) - link2link2nobody.toPath().deleteIfExists(); + Files.deleteIfExists(link2link2nobody.toPath()); } /** * Creates a sym link source->target */ static void mklink(File source, File target) throws IOException { - source.toPath().createSymbolicLink(target.toPath()); + Files.createSymbolicLink(source.toPath(), target.toPath()); } /** * Returns true if the "link" exists and is a sym link. */ static boolean isSymLink(File link) { - try { - BasicFileAttributes attrs = - Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS); - return attrs.isSymbolicLink(); - } catch (IOException x) { - return false; - } + return Files.isSymbolicLink(link.toPath()); } /** @@ -120,7 +114,7 @@ public class SymLinks { */ static long lastModifiedOfSymLink(File link) throws IOException { BasicFileAttributes attrs = - Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS); + Files.readAttributes(link.toPath(), BasicFileAttributes.class, NOFOLLOW_LINKS); assertTrue(attrs.isSymbolicLink()); return attrs.lastModifiedTime().toMillis(); } @@ -133,8 +127,8 @@ public class SymLinks { Path link = dir.toPath().resolve("link"); Path target = dir.toPath().resolve("target"); try { - link.createSymbolicLink(target); - link.delete(); + Files.createSymbolicLink(link, target); + Files.delete(link); return true; } catch (UnsupportedOperationException x) { return false; @@ -224,7 +218,7 @@ public class SymLinks { assertTrue(isSymLink(link2nobody)); } finally { - link.toPath().deleteIfExists(); + Files.deleteIfExists(link.toPath()); } header("renameTo"); @@ -287,8 +281,8 @@ public class SymLinks { // on Windows we test with the DOS hidden attribute set if (System.getProperty("os.name").startsWith("Windows")) { - DosFileAttributeView view = file.toPath() - .getFileAttributeView(DosFileAttributeView.class); + DosFileAttributeView view = Files + .getFileAttributeView(file.toPath(), DosFileAttributeView.class); view.setHidden(true); try { assertTrue(file.isHidden()); diff --git a/test/java/io/FileInputStream/LargeFileAvailable.java b/test/java/io/FileInputStream/LargeFileAvailable.java index 35c9ce47483bc234609a67ae3ba22ea5208b2542..0e33d9a969fd5f62d650a24ee441ebbb4943d6a7 100644 --- a/test/java/io/FileInputStream/LargeFileAvailable.java +++ b/test/java/io/FileInputStream/LargeFileAvailable.java @@ -31,6 +31,7 @@ import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.*; +import java.nio.file.Files; import static java.nio.file.StandardOpenOption.*; public class LargeFileAvailable { @@ -85,7 +86,7 @@ public class LargeFileAvailable { // Create a large file as a sparse file if possible File largefile = File.createTempFile("largefile", null); // re-create as a sparse file - largefile.toPath().delete(); + Files.delete(largefile.toPath()); try (FileChannel fc = FileChannel.open(largefile.toPath(), CREATE_NEW, WRITE, SPARSE)) { diff --git a/test/java/nio/channels/FileChannel/AtomicAppend.java b/test/java/nio/channels/FileChannel/AtomicAppend.java index 1420318d5d7efbf971814ecef816c9f6b5748e85..60bd746f123b1cba2ee57dccdc2f4cafcd7f7227 100644 --- a/test/java/nio/channels/FileChannel/AtomicAppend.java +++ b/test/java/nio/channels/FileChannel/AtomicAppend.java @@ -36,6 +36,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.nio.file.Files; import static java.nio.file.StandardOpenOption.*; public class AtomicAppend { @@ -55,7 +56,7 @@ public class AtomicAppend { if (rand.nextBoolean()) { return new FileOutputStream(file, true); } else { - return file.toPath().newOutputStream(APPEND); + return Files.newOutputStream(file.toPath(), APPEND); } } diff --git a/test/java/nio/channels/FileChannel/Transfer.java b/test/java/nio/channels/FileChannel/Transfer.java index f0507b5249fcfe749d5431390a5017365c47d9ba..565f8ff100761bb7e0046cad95e675456e0dab5a 100644 --- a/test/java/nio/channels/FileChannel/Transfer.java +++ b/test/java/nio/channels/FileChannel/Transfer.java @@ -276,7 +276,7 @@ public class Transfer { while (fc == null) { sink = File.createTempFile("sink", null); // re-create as a sparse file - sink.toPath().delete(); + sink.delete(); try { fc = FileChannel.open(sink.toPath(), StandardOpenOption.CREATE_NEW, diff --git a/test/java/nio/file/DirectoryStream/Basic.java b/test/java/nio/file/DirectoryStream/Basic.java index 75d66280147486ead164c191c2d74d8b39906717..69f5d18f656a7ac60416c606e1791f447448aea8 100644 --- a/test/java/nio/file/DirectoryStream/Basic.java +++ b/test/java/nio/file/DirectoryStream/Basic.java @@ -28,6 +28,7 @@ */ import java.nio.file.*; +import static java.nio.file.Files.*; import java.util.*; import java.io.IOException; @@ -38,29 +39,26 @@ public class Basic { DirectoryStream stream; // test that directory is empty - stream = dir.newDirectoryStream(); - try { - if (stream.iterator().hasNext()) + try (DirectoryStream ds = newDirectoryStream(dir)) { + if (ds.iterator().hasNext()) throw new RuntimeException("directory not empty"); - } finally { - stream.close(); } // create file in directory final Path foo = Paths.get("foo"); - dir.resolve(foo).createFile(); + createFile(dir.resolve(foo)); // iterate over directory and check there is one entry - stream = dir.newDirectoryStream(); + stream = newDirectoryStream(dir); found = false; try { for (Path entry: stream) { - if (entry.getName().equals(foo)) { + if (entry.getFileName().equals(foo)) { if (found) throw new RuntimeException("entry already found"); found = true; } else { - throw new RuntimeException("entry " + entry.getName() + + throw new RuntimeException("entry " + entry.getFileName() + " not expected"); } } @@ -71,21 +69,18 @@ public class Basic { throw new RuntimeException("entry not found"); // check filtering: f* should match foo - DirectoryStream.Filter filter = new DirectoryStream.Filter() { + DirectoryStream.Filter filter = new DirectoryStream.Filter<>() { private PathMatcher matcher = dir.getFileSystem().getPathMatcher("glob:f*"); public boolean accept(Path file) { return matcher.matches(file); } }; - stream = dir.newDirectoryStream(filter); - try { - for (Path entry: stream) { - if (!entry.getName().equals(foo)) + try (DirectoryStream ds = newDirectoryStream(dir, filter)) { + for (Path entry: ds) { + if (!entry.getFileName().equals(foo)) throw new RuntimeException("entry not expected"); } - } finally { - stream.close(); } // check filtering: z* should not match any files @@ -96,12 +91,9 @@ public class Basic { return matcher.matches(file); } }; - stream = dir.newDirectoryStream(filter); - try { - if (stream.iterator().hasNext()) + try (DirectoryStream ds = newDirectoryStream(dir, filter)) { + if (ds.iterator().hasNext()) throw new RuntimeException("no matching entries expected"); - } finally { - stream.close(); } // check that an IOException thrown by a filter is propagated @@ -110,7 +102,7 @@ public class Basic { throw new java.util.zip.ZipException(); } }; - stream = dir.newDirectoryStream(filter); + stream = newDirectoryStream(dir, filter); try { stream.iterator().hasNext(); throw new RuntimeException("DirectoryIteratorException expected"); @@ -124,7 +116,7 @@ public class Basic { // check that exception or error thrown by filter is not thrown // by newDirectoryStream or iterator method. - stream = dir.newDirectoryStream(new DirectoryStream.Filter() { + stream = newDirectoryStream(dir, new DirectoryStream.Filter() { public boolean accept(Path file) { throw new RuntimeException("Should not be visible"); } @@ -137,13 +129,13 @@ public class Basic { // test NotDirectoryException try { - dir.resolve(foo).newDirectoryStream(); + newDirectoryStream(dir.resolve(foo)); throw new RuntimeException("NotDirectoryException not thrown"); } catch (NotDirectoryException x) { } // test UnsupportedOperationException - stream = dir.newDirectoryStream(); + stream = newDirectoryStream(dir); Iterator i = stream.iterator(); i.next(); try { @@ -153,7 +145,7 @@ public class Basic { } // test IllegalStateException - stream = dir.newDirectoryStream(); + stream = newDirectoryStream(dir); stream.iterator(); try { // attempt to obtain second iterator @@ -163,7 +155,7 @@ public class Basic { } stream.close(); - stream = dir.newDirectoryStream(); + stream = newDirectoryStream(dir); stream.close(); try { // attempt to obtain iterator after stream is closed @@ -173,13 +165,13 @@ public class Basic { } // test that iterator reads to end of stream when closed - stream = dir.newDirectoryStream(); + stream = newDirectoryStream(dir); i = stream.iterator(); stream.close(); while (i.hasNext()) i.next(); - stream = dir.newDirectoryStream(); + stream = newDirectoryStream(dir); i = stream.iterator(); stream.close(); try { diff --git a/test/java/nio/file/DirectoryStream/DriveLetter.java b/test/java/nio/file/DirectoryStream/DriveLetter.java index e692a7ec55f6654bc1ccc60c204a0286dcab03f1..a629a027d39093cc6df26e3d734d25d6fa0990ba 100644 --- a/test/java/nio/file/DirectoryStream/DriveLetter.java +++ b/test/java/nio/file/DirectoryStream/DriveLetter.java @@ -52,16 +52,14 @@ public class DriveLetter { Path expected = Paths.get(drive).resolve(tempFile.getName()); boolean found = false; - DirectoryStream stream = Paths.get(drive).newDirectoryStream(); - try { + Path dir = Paths.get(drive); + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { for (Path file : stream) { if (file.equals(expected)) { found = true; break; } } - } finally { - stream.close(); } if (!found) throw new RuntimeException("Temporary file not found???"); diff --git a/test/java/nio/file/DirectoryStream/SecureDS.java b/test/java/nio/file/DirectoryStream/SecureDS.java index e776c8b31adf24d5c4fd0bf56243f3068207be55..fdfcfd9fdfe73b01eda544ae6eb6c54a7877cfd0 100644 --- a/test/java/nio/file/DirectoryStream/SecureDS.java +++ b/test/java/nio/file/DirectoryStream/SecureDS.java @@ -28,6 +28,7 @@ */ import java.nio.file.*; +import static java.nio.file.Files.*; import static java.nio.file.StandardOpenOption.*; import static java.nio.file.LinkOption.*; import java.nio.file.attribute.*; @@ -41,7 +42,7 @@ public class SecureDS { public static void main(String[] args) throws IOException { Path dir = TestUtil.createTemporaryDirectory(); try { - DirectoryStream stream = dir.newDirectoryStream(); + DirectoryStream stream = newDirectoryStream(dir); stream.close(); if (!(stream instanceof SecureDirectoryStream)) { System.out.println("SecureDirectoryStream not supported."); @@ -62,28 +63,28 @@ public class SecureDS { // Exercise each of SecureDirectoryStream's method (except move) static void doBasicTests(Path dir) throws IOException { - Path dir1 = dir.resolve("dir1").createDirectory(); + Path dir1 = createDirectory(dir.resolve("dir1")); Path dir2 = dir.resolve("dir2"); // create a file, directory, and two sym links in the directory Path fileEntry = Paths.get("myfile"); - dir1.resolve(fileEntry).createFile(); + createFile(dir1.resolve(fileEntry)); Path dirEntry = Paths.get("mydir"); - dir1.resolve(dirEntry).createDirectory(); + createDirectory(dir1.resolve(dirEntry)); // myfilelink -> myfile Path link1Entry = Paths.get("myfilelink"); if (supportsLinks) - dir1.resolve(link1Entry).createSymbolicLink(fileEntry); + createSymbolicLink(dir1.resolve(link1Entry), fileEntry); // mydirlink -> mydir Path link2Entry = Paths.get("mydirlink"); if (supportsLinks) - dir1.resolve(link2Entry).createSymbolicLink(dirEntry); + createSymbolicLink(dir1.resolve(link2Entry), dirEntry); // open directory and then move it so that it is no longer accessible // via its original path. SecureDirectoryStream stream = - (SecureDirectoryStream)dir1.newDirectoryStream(); - dir1.moveTo(dir2); + (SecureDirectoryStream)newDirectoryStream(dir1); + move(dir1, dir2); // Test: iterate over all entries int count = 0; @@ -138,7 +139,7 @@ public class SecureDS { if (supportsLinks) { stream.newByteChannel(link1Entry, opts).close(); try { - Set mixed = new HashSet(); + Set mixed = new HashSet<>(); mixed.add(READ); mixed.add(NOFOLLOW_LINKS); stream.newByteChannel(link1Entry, mixed).close(); @@ -168,51 +169,48 @@ public class SecureDS { // clean-up stream.close(); - dir2.delete(); + delete(dir2); } // Exercise SecureDirectoryStream's move method static void doMoveTests(Path dir) throws IOException { - Path dir1 = dir.resolve("dir1").createDirectory(); - Path dir2 = dir.resolve("dir2").createDirectory(); + Path dir1 = createDirectory(dir.resolve("dir1")); + Path dir2 = createDirectory(dir.resolve("dir2")); // create dir1/myfile, dir1/mydir, dir1/mylink Path fileEntry = Paths.get("myfile"); - dir1.resolve(fileEntry).createFile(); + createFile(dir1.resolve(fileEntry)); Path dirEntry = Paths.get("mydir"); - dir1.resolve(dirEntry).createDirectory(); + createDirectory(dir1.resolve(dirEntry)); Path linkEntry = Paths.get("mylink"); if (supportsLinks) - dir1.resolve(linkEntry).createSymbolicLink(Paths.get("missing")); + createSymbolicLink(dir1.resolve(linkEntry), Paths.get("missing")); // target name Path target = Paths.get("newfile"); // open stream to both directories SecureDirectoryStream stream1 = - (SecureDirectoryStream)dir1.newDirectoryStream(); + (SecureDirectoryStream)newDirectoryStream(dir1); SecureDirectoryStream stream2 = - (SecureDirectoryStream)dir2.newDirectoryStream(); + (SecureDirectoryStream)newDirectoryStream(dir2); // Test: move dir1/myfile -> dir2/newfile stream1.move(fileEntry, stream2, target); - assertTrue(dir1.resolve(fileEntry).notExists()); - assertTrue(dir2.resolve(target).exists()); + assertTrue(notExists(dir1.resolve(fileEntry))); + assertTrue(exists(dir2.resolve(target))); stream2.deleteFile(target); // Test: move dir1/mydir -> dir2/newfile stream1.move(dirEntry, stream2, target); - assertTrue(dir1.resolve(dirEntry).notExists()); - assertTrue(dir2.resolve(target).exists()); + assertTrue(notExists(dir1.resolve(dirEntry))); + assertTrue(exists(dir2.resolve(target))); stream2.deleteDirectory(target); // Test: move dir1/mylink -> dir2/newfile if (supportsLinks) { stream1.move(linkEntry, stream2, target); - assertTrue(dir2.resolve(target) - .getFileAttributeView(BasicFileAttributeView.class, NOFOLLOW_LINKS) - .readAttributes() - .isSymbolicLink()); + assertTrue(isSymbolicLink(dir2.resolve(target))); stream2.deleteFile(target); } @@ -220,10 +218,10 @@ public class SecureDS { String testDirAsString = System.getProperty("test.dir"); if (testDirAsString != null) { Path testDir = Paths.get(testDirAsString); - if (!dir1.getFileStore().equals(testDir.getFileStore())) { + if (!getFileStore(dir1).equals(getFileStore(testDir))) { SecureDirectoryStream ts = - (SecureDirectoryStream)testDir.newDirectoryStream(); - dir1.resolve(fileEntry).createFile(); + (SecureDirectoryStream)newDirectoryStream(testDir); + createFile(dir1.resolve(fileEntry)); try { stream1.move(fileEntry, ts, target); shouldNotGetHere(); @@ -234,17 +232,17 @@ public class SecureDS { } // clean-up - dir1.delete(); - dir2.delete(); + delete(dir1); + delete(dir2); } // null and ClosedDirectoryStreamException static void miscTests(Path dir) throws IOException { Path file = Paths.get("file"); - dir.resolve(file).createFile(); + createFile(dir.resolve(file)); SecureDirectoryStream stream = - (SecureDirectoryStream)dir.newDirectoryStream(); + (SecureDirectoryStream)newDirectoryStream(dir); // NullPointerException try { @@ -319,7 +317,7 @@ public class SecureDS { } catch (ClosedDirectoryStreamException x) { } // clean-up - dir.resolve(file).delete(); + delete(dir.resolve(file)); } static void assertTrue(boolean b) { diff --git a/test/java/nio/file/FileStore/Basic.java b/test/java/nio/file/FileStore/Basic.java index 0b43109d3a0f07ffbcb8623898feb08e31a49edf..f49bc6552bb83da3fbec66c6dad96219c7916540 100644 --- a/test/java/nio/file/FileStore/Basic.java +++ b/test/java/nio/file/FileStore/Basic.java @@ -22,18 +22,21 @@ */ /* @test - * @bug 4313887 6873621 6979526 + * @bug 4313887 6873621 6979526 7006126 * @summary Unit test for java.nio.file.FileStore * @library .. */ import java.nio.file.*; import java.nio.file.attribute.*; +import java.io.File; import java.io.IOException; import java.util.*; public class Basic { + static final long G = 1024L * 1024L * 1024L; + public static void main(String[] args) throws IOException { Path dir = TestUtil.createTemporaryDirectory(); try { @@ -48,17 +51,25 @@ public class Basic { throw new RuntimeException("Assertion failed"); } + static void checkWithin1GB(long value1, long value2) { + long diff = Math.abs(value1 - value2); + if (diff > G) + throw new RuntimeException("values differ by more than 1GB"); + } + static void doTests(Path dir) throws IOException { /** * Test: Directory should be on FileStore that is writable */ - assertTrue(!dir.getFileStore().isReadOnly()); + assertTrue(!Files.getFileStore(dir).isReadOnly()); /** * Test: Two files should have the same FileStore */ - FileStore store1 = dir.resolve("foo").createFile().getFileStore(); - FileStore store2 = dir.resolve("bar").createFile().getFileStore(); + Path file1 = Files.createFile(dir.resolve("foo")); + Path file2 = Files.createFile(dir.resolve("bar")); + FileStore store1 = Files.getFileStore(file1); + FileStore store2 = Files.getFileStore(file2); assertTrue(store1.equals(store2)); assertTrue(store2.equals(store1)); assertTrue(store1.hashCode() == store2.hashCode()); @@ -77,6 +88,24 @@ public class Basic { assertTrue(store1.supportsFileAttributeView("user") == store1.supportsFileAttributeView(UserDefinedFileAttributeView.class)); + /** + * Test: Space atributes + */ + File f = file1.toFile(); + long total = f.getTotalSpace(); + long free = f.getFreeSpace(); + long usable = f.getUsableSpace(); + + // check values are "close" + checkWithin1GB(total, store1.getTotalSpace()); + checkWithin1GB(free, store1.getUnallocatedSpace()); + checkWithin1GB(usable, store1.getUsableSpace()); + + // get values by name + checkWithin1GB(total, (Long)store1.getAttribute("totalSpace")); + checkWithin1GB(free, (Long)store1.getAttribute("unallocatedSpace")); + checkWithin1GB(usable, (Long)store1.getAttribute("usableSpace")); + /** * Test: Enumerate all FileStores */ @@ -85,8 +114,10 @@ public class Basic { System.out.format("%s (name=%s type=%s)\n", store, store.name(), store.type()); - // check space attributes - Attributes.readFileStoreSpaceAttributes(store); + // check space attributes are accessible + store.getTotalSpace(); + store.getUnallocatedSpace(); + store.getUsableSpace(); // two distinct FileStores should not be equal assertTrue(!store.equals(prev)); diff --git a/test/java/nio/file/Files/BytesAndLines.java b/test/java/nio/file/Files/BytesAndLines.java new file mode 100644 index 0000000000000000000000000000000000000000..2833c99cb73ad4fcd04fff0670617390daadc46b --- /dev/null +++ b/test/java/nio/file/Files/BytesAndLines.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2011, 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 7006126 + * @summary Unit test for methods for Files readAllBytes, readAllLines and + * and write methods. + */ + +import java.nio.file.*; +import static java.nio.file.Files.*; +import java.io.*; +import java.util.*; +import java.nio.charset.*; + +public class BytesAndLines { + static final Random rand = new Random(); + + static final Charset US_ASCII = Charset.forName("US-ASCII"); + + public static void main(String[] args) throws IOException { + testReadAndWriteBytes(); + testReadLines(); + testWriteLines(); + } + + /** + * Test readAllBytes(Path) and write(Path, byte[], OpenOption...) + */ + static void testReadAndWriteBytes() throws IOException { + // exercise methods with various sizes + testReadAndWriteBytes(0); + for (int i=0; i<100; i++) { + testReadAndWriteBytes(rand.nextInt(32000)); + } + + // NullPointerException + Path file = Paths.get("foo"); + List lines = Collections.emptyList(); + try { + readAllBytes(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + write(null, lines, Charset.defaultCharset()); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + write(file, null, Charset.defaultCharset()); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + write(file, lines, null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + write(file, lines, Charset.defaultCharset(), (OpenOption[])null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + OpenOption[] opts = { null }; + write(file, lines, Charset.defaultCharset(), opts); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + } + + + static void testReadAndWriteBytes(int size) throws IOException { + Path path = createTempFile("blah", null); + try { + boolean append = rand.nextBoolean(); + + byte[] b1 = new byte[size]; + rand.nextBytes(b1); + + byte[] b2 = (append) ? new byte[size] : new byte[0]; + rand.nextBytes(b2); + + // write method should create file if it doesn't exist + if (rand.nextBoolean()) + delete(path); + + // write bytes to file + Path target = write(path, b1); + assertTrue(target==path, "Unexpected path"); + assertTrue(size(path) == b1.length, "Unexpected file size"); + + // append bytes to file (might be 0 bytes) + write(path, b2, StandardOpenOption.APPEND); + assertTrue(size(path) == b1.length + b2.length, "Unexpected file size"); + + // read entire file + byte[] read = readAllBytes(path); + + // check bytes are correct + byte[] expected; + if (append) { + expected = new byte[b1.length + b2.length]; + System.arraycopy(b1, 0, expected, 0, b1.length); + System.arraycopy(b2, 0, expected, b1.length, b2.length); + } else { + expected = b1; + } + assertTrue(Arrays.equals(read, expected), + "Bytes read not the same as bytes written"); + } finally { + deleteIfExists(path); + } + } + + /** + * Test readAllLines(Path,Charset) + */ + static void testReadLines() throws IOException { + Path tmpfile = createTempFile("blah", "txt"); + try { + List lines; + + // zero lines + assertTrue(size(tmpfile) == 0, "File should be empty"); + lines = readAllLines(tmpfile, US_ASCII); + assertTrue(lines.isEmpty(), "No line expected"); + + // one line + byte[] hi = { (byte)'h', (byte)'i' }; + write(tmpfile, hi); + lines = readAllLines(tmpfile, US_ASCII); + assertTrue(lines.size() == 1, "One line expected"); + assertTrue(lines.get(0).equals("hi"), "'Hi' expected"); + + // two lines using platform's line separator + List expected = Arrays.asList("hi", "there"); + write(tmpfile, expected, US_ASCII); + assertTrue(size(tmpfile) > 0, "File is empty"); + lines = readAllLines(tmpfile, US_ASCII); + assertTrue(lines.equals(expected), "Unexpected lines"); + + // MalformedInputException + byte[] bad = { (byte)0xff, (byte)0xff }; + write(tmpfile, bad); + try { + readAllLines(tmpfile, US_ASCII); + throw new RuntimeException("MalformedInputException expected"); + } catch (MalformedInputException ignore) { } + + + // NullPointerException + try { + readAllLines(null, US_ASCII); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + readAllLines(tmpfile, null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + + } finally { + delete(tmpfile); + } + } + + /** + * Test write(Path,Iterable,Charset,OpenOption...) + */ + static void testWriteLines() throws IOException { + Path tmpfile = createTempFile("blah", "txt"); + try { + // write method should create file if it doesn't exist + if (rand.nextBoolean()) + delete(tmpfile); + + // zero lines + Path result = write(tmpfile, Collections.emptyList(), US_ASCII); + assert(size(tmpfile) == 0); + assert(result == tmpfile); + + // two lines + List lines = Arrays.asList("hi", "there"); + write(tmpfile, lines, US_ASCII); + List actual = readAllLines(tmpfile, US_ASCII); + assertTrue(actual.equals(lines), "Unexpected lines"); + + // append two lines + write(tmpfile, lines, US_ASCII, StandardOpenOption.APPEND); + List expected = new ArrayList(); + expected.addAll(lines); + expected.addAll(lines); + assertTrue(expected.size() == 4, "List should have 4 elements"); + actual = readAllLines(tmpfile, US_ASCII); + assertTrue(actual.equals(expected), "Unexpected lines"); + + // UnmappableCharacterException + try { + String s = "\u00A0\u00A1"; + write(tmpfile, Arrays.asList(s), US_ASCII); + throw new RuntimeException("UnmappableCharacterException expected"); + } catch (UnmappableCharacterException ignore) { } + + // NullPointerException + try { + write(null, lines, US_ASCII); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + write(tmpfile, null, US_ASCII); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + write(tmpfile, lines, null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + write(tmpfile, lines, US_ASCII, (OpenOption[])null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + OpenOption[] opts = { (OpenOption)null }; + write(tmpfile, lines, US_ASCII, opts); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + + } finally { + delete(tmpfile); + } + + } + + static void assertTrue(boolean expr, String errmsg) { + if (!expr) + throw new RuntimeException(errmsg); + } +} diff --git a/test/java/nio/file/Path/CheckPermissions.java b/test/java/nio/file/Files/CheckPermissions.java similarity index 70% rename from test/java/nio/file/Path/CheckPermissions.java rename to test/java/nio/file/Files/CheckPermissions.java index 9996ac7490f965aa45a0f3c277d0bee548b80619..8137a358d42cd07a56478c52089a3b99bf5c7c19 100644 --- a/test/java/nio/file/Path/CheckPermissions.java +++ b/test/java/nio/file/Files/CheckPermissions.java @@ -22,8 +22,8 @@ */ /* @test - * @bug 6866804 - * @summary Unit test for java.nio.file.Path + * @bug 6866804 7006126 + * @summary Unit test for java.nio.file.Files * @library .. * @build CheckPermissions * @run main/othervm CheckPermissions @@ -31,6 +31,8 @@ import java.nio.ByteBuffer; import java.nio.file.*; +import static java.nio.file.Files.*; +import static java.nio.file.StandardOpenOption.*; import java.nio.file.attribute.*; import java.nio.channels.SeekableByteChannel; import java.security.Permission; @@ -45,12 +47,12 @@ import java.util.*; public class CheckPermissions { static class Checks { - private List permissionsChecked = new ArrayList(); - private Set propertiesChecked = new HashSet(); - private List readsChecked = new ArrayList(); - private List writesChecked = new ArrayList(); - private List deletesChecked = new ArrayList(); - private List execsChecked = new ArrayList(); + private List permissionsChecked = new ArrayList<>(); + private Set propertiesChecked = new HashSet<>(); + private List readsChecked = new ArrayList<>(); + private List writesChecked = new ArrayList<>(); + private List deletesChecked = new ArrayList<>(); + private List execsChecked = new ArrayList<>(); List permissionsChecked() { return permissionsChecked; } Set propertiesChecked() { return propertiesChecked; } @@ -78,7 +80,7 @@ public class CheckPermissions { if (type.isInstance(perm) && perm.getName().equals(name)) return; } - throw new RuntimeException(type.getName() + "\"" + name + "\") not checked"); + throw new RuntimeException(type.getName() + "(\"" + name + "\") not checked"); } static void assertCheckPropertyAccess(String key) { @@ -103,6 +105,17 @@ public class CheckPermissions { assertChecked(file, myChecks.get().writesChecked()); } + static void assertCheckWriteToDirectory(Path dir) { + String s = dir.toString(); + List list = myChecks.get().writesChecked(); + for (String f: list) { + if (f.startsWith(s)) { + return; + } + } + throw new RuntimeException("Access not checked"); + } + static void assertCheckDelete(Path file) { assertChecked(file, myChecks.get().deletesChecked()); } @@ -197,215 +210,240 @@ public class CheckPermissions { } public static void main(String[] args) throws IOException { - Path dir = Paths.get(System.getProperty("test.dir", ".")); - Path file = dir.resolve("file1234").createFile(); + final Path testdir = Paths.get(System.getProperty("test.dir", ".")).toAbsolutePath(); + final Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); + + Path file = createFile(testdir.resolve("file1234")); try { LoggingSecurityManager.install(); - // -- checkAccess -- + // -- check access -- prepare(); - file.checkAccess(); + exists(file); assertCheckRead(file); prepare(); - file.checkAccess(AccessMode.READ); + isReadable(file); assertCheckRead(file); prepare(); - file.checkAccess(AccessMode.WRITE); + isWritable(file); assertCheckWrite(file); prepare(); - try { - file.checkAccess(AccessMode.EXECUTE); - } catch (AccessDeniedException x) { } + isExecutable(file); assertCheckExec(file); - prepare(); - try { - file.checkAccess(AccessMode.READ, AccessMode.WRITE, AccessMode.EXECUTE); - } catch (AccessDeniedException x) { } - assertCheckRead(file); - assertCheckWrite(file); - assertCheckExec(file); - - // -- copyTo -- + // -- copy -- - Path target = dir.resolve("target1234"); + Path target = testdir.resolve("target1234"); prepare(); - file.copyTo(target); + copy(file, target); try { assertCheckRead(file); assertCheckWrite(target); } finally { - target.delete(); + delete(target); } - if (TestUtil.supportsLinks(dir)) { - Path link = dir.resolve("link1234").createSymbolicLink(file); + if (TestUtil.supportsLinks(testdir)) { + Path link = testdir.resolve("link1234"); + createSymbolicLink(link, file); try { prepare(); - link.copyTo(target, LinkOption.NOFOLLOW_LINKS); + copy(link, target, LinkOption.NOFOLLOW_LINKS); try { assertCheckRead(link); assertCheckWrite(target); assertCheckPermission(LinkPermission.class, "symbolic"); } finally { - target.delete(); + delete(target); } } finally { - link.delete(); + delete(link); } } // -- createDirectory -- - Path subdir = dir.resolve("subdir1234"); + Path subdir = testdir.resolve("subdir1234"); prepare(); - subdir.createDirectory(); + createDirectory(subdir); try { assertCheckWrite(subdir); } finally { - subdir.delete(); + delete(subdir); } // -- createFile -- - Path fileToCreate = dir.resolve("file7890"); + Path fileToCreate = testdir.resolve("file7890"); prepare(); + createFile(fileToCreate); try { - fileToCreate.createFile(); assertCheckWrite(fileToCreate); } finally { - fileToCreate.delete(); + delete(fileToCreate); } // -- createSymbolicLink -- - if (TestUtil.supportsLinks(dir)) { + if (TestUtil.supportsLinks(testdir)) { prepare(); - Path link = dir.resolve("link1234").createSymbolicLink(file); + Path link = testdir.resolve("link1234"); + createSymbolicLink(link, file); try { assertCheckWrite(link); assertCheckPermission(LinkPermission.class, "symbolic"); } finally { - link.delete(); + delete(link); + } + } + + // -- createLink -- + + if (TestUtil.supportsLinks(testdir)) { + prepare(); + Path link = testdir.resolve("entry234"); + createLink(link, file); + try { + assertCheckWrite(link); + assertCheckPermission(LinkPermission.class, "hard"); + } finally { + delete(link); } } + // -- createTempFile -- + + prepare(); + Path tmpfile1 = createTempFile("foo", null); + try { + assertCheckWriteToDirectory(tmpdir); + } finally { + delete(tmpfile1); + } + prepare(); + Path tmpfile2 = createTempFile(testdir, "foo", ".tmp"); + try { + assertCheckWriteToDirectory(testdir); + } finally { + delete(tmpfile2); + } + + // -- createTempDirectory -- + + prepare(); + Path tmpdir1 = createTempDirectory("foo"); + try { + assertCheckWriteToDirectory(tmpdir); + } finally { + delete(tmpdir1); + } + prepare(); + Path tmpdir2 = createTempDirectory(testdir, "foo"); + try { + assertCheckWriteToDirectory(testdir); + } finally { + delete(tmpdir2); + } + // -- delete/deleteIfExists -- - Path fileToDelete = dir.resolve("file7890"); + Path fileToDelete = testdir.resolve("file7890"); - fileToDelete.createFile(); + createFile(fileToDelete); prepare(); - fileToDelete.delete(); + delete(fileToDelete); assertCheckDelete(fileToDelete); - fileToDelete.createFile(); + createFile(fileToDelete); prepare(); - fileToDelete.deleteIfExists(); + deleteIfExists(fileToDelete); // file exists + assertCheckDelete(fileToDelete); + + prepare(); + deleteIfExists(fileToDelete); // file does not exist assertCheckDelete(fileToDelete); // -- exists/notExists -- prepare(); - file.exists(); + exists(file); assertCheckRead(file); prepare(); - file.notExists(); + notExists(file); assertCheckRead(file); // -- getFileStore -- prepare(); - file.getFileStore(); + getFileStore(file); assertCheckRead(file); assertCheckPermission(RuntimePermission.class, "getFileStoreAttributes"); // -- isSameFile -- prepare(); - file.isSameFile(dir); + isSameFile(file, testdir); assertCheckRead(file); - assertCheckRead(dir); + assertCheckRead(testdir); - // -- moveTo -- + // -- move -- - Path target2 = dir.resolve("target1234"); + Path target2 = testdir.resolve("target1234"); prepare(); - file.moveTo(target2); + move(file, target2); try { assertCheckWrite(file); assertCheckWrite(target2); } finally { // restore file - target2.moveTo(file); + move(target2, file); } // -- newByteChannel -- - SeekableByteChannel sbc; - prepare(); - sbc = file.newByteChannel(); - try { + try (SeekableByteChannel sbc = newByteChannel(file)) { assertCheckRead(file); - } finally { - sbc.close(); } prepare(); - sbc = file.newByteChannel(StandardOpenOption.WRITE); - try { + try (SeekableByteChannel sbc = newByteChannel(file, WRITE)) { assertCheckWrite(file); - } finally { - sbc.close(); } prepare(); - sbc = file.newByteChannel(StandardOpenOption.READ, StandardOpenOption.WRITE); - try { + try (SeekableByteChannel sbc = newByteChannel(file, READ, WRITE)) { assertCheckRead(file); assertCheckWrite(file); - } finally { - sbc.close(); } prepare(); - sbc = file.newByteChannel(StandardOpenOption.DELETE_ON_CLOSE); - try { + try (SeekableByteChannel sbc = newByteChannel(file, DELETE_ON_CLOSE)) { assertCheckRead(file); assertCheckDelete(file); - } finally { - sbc.close(); } - file.createFile(); // restore file + createFile(file); // restore file // -- newInputStream/newOutptuStream -- prepare(); - InputStream in = file.newInputStream(); - try { + try (InputStream in = newInputStream(file)) { assertCheckRead(file); - } finally { - in.close(); } prepare(); - OutputStream out = file.newOutputStream(); - try { + try (OutputStream out = newOutputStream(file)) { assertCheckWrite(file); - } finally { - out.close(); } // -- newDirectoryStream -- prepare(); - DirectoryStream stream = dir.newDirectoryStream(); - try { - assertCheckRead(dir); + try (DirectoryStream stream = newDirectoryStream(testdir)) { + assertCheckRead(testdir); if (stream instanceof SecureDirectoryStream) { Path entry; @@ -413,63 +451,57 @@ public class CheckPermissions { (SecureDirectoryStream)stream; // newByteChannel - entry = file.getName(); + entry = file.getFileName(); prepare(); - sbc = sds.newByteChannel(entry, EnumSet.of(StandardOpenOption.READ)); - try { + try (SeekableByteChannel sbc = sds.newByteChannel(entry, EnumSet.of(READ))) { assertCheckRead(file); - } finally { - sbc.close(); } prepare(); - sbc = sds.newByteChannel(entry, EnumSet.of(StandardOpenOption.WRITE)); - try { + try (SeekableByteChannel sbc = sds.newByteChannel(entry, EnumSet.of(WRITE))) { assertCheckWrite(file); - } finally { - sbc.close(); } // deleteFile - entry = file.getName(); + entry = file.getFileName(); prepare(); sds.deleteFile(entry); assertCheckDelete(file); - dir.resolve(entry).createFile(); // restore file + createFile(testdir.resolve(entry)); // restore file // deleteDirectory entry = Paths.get("subdir1234"); - dir.resolve(entry).createDirectory(); + createDirectory(testdir.resolve(entry)); prepare(); sds.deleteDirectory(entry); - assertCheckDelete(dir.resolve(entry)); + assertCheckDelete(testdir.resolve(entry)); // move entry = Paths.get("tempname1234"); prepare(); - sds.move(file.getName(), sds, entry); + sds.move(file.getFileName(), sds, entry); assertCheckWrite(file); - assertCheckWrite(dir.resolve(entry)); - sds.move(entry, sds, file.getName()); // restore file + assertCheckWrite(testdir.resolve(entry)); + sds.move(entry, sds, file.getFileName()); // restore file // newDirectoryStream entry = Paths.get("subdir1234"); - dir.resolve(entry).createDirectory(); + createDirectory(testdir.resolve(entry)); try { prepare(); sds.newDirectoryStream(entry).close(); - assertCheckRead(dir.resolve(entry)); + assertCheckRead(testdir.resolve(entry)); } finally { - dir.resolve(entry).delete(); + delete(testdir.resolve(entry)); } // getFileAttributeView to access attributes of directory testBasicFileAttributeView(sds - .getFileAttributeView(BasicFileAttributeView.class), dir); + .getFileAttributeView(BasicFileAttributeView.class), testdir); testPosixFileAttributeView(sds - .getFileAttributeView(PosixFileAttributeView.class), dir); + .getFileAttributeView(PosixFileAttributeView.class), testdir); // getFileAttributeView to access attributes of entry - entry = file.getName(); + entry = file.getFileName(); testBasicFileAttributeView(sds .getFileAttributeView(entry, BasicFileAttributeView.class), file); testPosixFileAttributeView(sds @@ -478,15 +510,12 @@ public class CheckPermissions { } else { System.out.println("SecureDirectoryStream not tested"); } - - } finally { - stream.close(); } // -- toAbsolutePath -- prepare(); - file.getName().toAbsolutePath(); + file.getFileName().toAbsolutePath(); assertCheckPropertyAccess("user.dir"); // -- toRealPath -- @@ -509,41 +538,38 @@ public class CheckPermissions { // -- register -- - WatchService watcher = FileSystems.getDefault().newWatchService(); - try { + try (WatchService watcher = FileSystems.getDefault().newWatchService()) { prepare(); - dir.register(watcher, StandardWatchEventKind.ENTRY_DELETE); - assertCheckRead(dir); - } finally { - watcher.close(); + testdir.register(watcher, StandardWatchEventKind.ENTRY_DELETE); + assertCheckRead(testdir); } // -- getAttribute/setAttribute/readAttributes -- prepare(); - file.getAttribute("size"); + getAttribute(file, "size"); assertCheckRead(file); prepare(); - file.setAttribute("lastModifiedTime", + setAttribute(file, "lastModifiedTime", FileTime.fromMillis(System.currentTimeMillis())); assertCheckWrite(file); prepare(); - file.readAttributes("*"); + readAttributes(file, "*"); assertCheckRead(file); // -- BasicFileAttributeView -- - testBasicFileAttributeView(file - .getFileAttributeView(BasicFileAttributeView.class), file); + testBasicFileAttributeView( + getFileAttributeView(file, BasicFileAttributeView.class), file); // -- PosixFileAttributeView -- { PosixFileAttributeView view = - file.getFileAttributeView(PosixFileAttributeView.class); + getFileAttributeView(file, PosixFileAttributeView.class); if (view != null && - file.getFileStore().supportsFileAttributeView(PosixFileAttributeView.class)) + getFileStore(file).supportsFileAttributeView(PosixFileAttributeView.class)) { testPosixFileAttributeView(view, file); } else { @@ -555,9 +581,9 @@ public class CheckPermissions { { DosFileAttributeView view = - file.getFileAttributeView(DosFileAttributeView.class); + getFileAttributeView(file, DosFileAttributeView.class); if (view != null && - file.getFileStore().supportsFileAttributeView(DosFileAttributeView.class)) + getFileStore(file).supportsFileAttributeView(DosFileAttributeView.class)) { prepare(); view.readAttributes(); @@ -587,9 +613,9 @@ public class CheckPermissions { { FileOwnerAttributeView view = - file.getFileAttributeView(FileOwnerAttributeView.class); + getFileAttributeView(file, FileOwnerAttributeView.class); if (view != null && - file.getFileStore().supportsFileAttributeView(FileOwnerAttributeView.class)) + getFileStore(file).supportsFileAttributeView(FileOwnerAttributeView.class)) { prepare(); UserPrincipal owner = view.getOwner(); @@ -610,9 +636,9 @@ public class CheckPermissions { { UserDefinedFileAttributeView view = - file.getFileAttributeView(UserDefinedFileAttributeView.class); + getFileAttributeView(file, UserDefinedFileAttributeView.class); if (view != null && - file.getFileStore().supportsFileAttributeView(UserDefinedFileAttributeView.class)) + getFileStore(file).supportsFileAttributeView(UserDefinedFileAttributeView.class)) { prepare(); view.write("test", ByteBuffer.wrap(new byte[100])); @@ -651,9 +677,9 @@ public class CheckPermissions { // -- AclFileAttributeView -- { AclFileAttributeView view = - file.getFileAttributeView(AclFileAttributeView.class); + getFileAttributeView(file, AclFileAttributeView.class); if (view != null && - file.getFileStore().supportsFileAttributeView(AclFileAttributeView.class)) + getFileStore(file).supportsFileAttributeView(AclFileAttributeView.class)) { prepare(); List acl = view.getAcl(); @@ -672,7 +698,7 @@ public class CheckPermissions { UserPrincipalLookupService lookupService = FileSystems.getDefault().getUserPrincipalLookupService(); - UserPrincipal owner = Attributes.getOwner(file); + UserPrincipal owner = getOwner(file); prepare(); lookupService.lookupPrincipalByName(owner.getName()); @@ -680,7 +706,7 @@ public class CheckPermissions { "lookupUserInformation"); try { - UserPrincipal group = Attributes.readPosixFileAttributes(file).group(); + UserPrincipal group = readAttributes(file, PosixFileAttributes.class).group(); prepare(); lookupService.lookupPrincipalByGroupName(group.getName()); assertCheckPermission(RuntimePermission.class, @@ -691,7 +717,7 @@ public class CheckPermissions { } finally { - file.deleteIfExists(); + deleteIfExists(file); } } } diff --git a/test/java/nio/file/Path/CopyAndMove.java b/test/java/nio/file/Files/CopyAndMove.java similarity index 63% rename from test/java/nio/file/Path/CopyAndMove.java rename to test/java/nio/file/Files/CopyAndMove.java index 17e3cab38e023e886e9ff67217ca0365cefbf333..c0d2ba6dd8facb9880e31f0fe9d4f49a7d44afe8 100644 --- a/test/java/nio/file/Path/CopyAndMove.java +++ b/test/java/nio/file/Files/CopyAndMove.java @@ -22,8 +22,8 @@ */ /* @test - * @bug 4313887 6838333 6917021 - * @summary Unit test for java.nio.file.Path copyTo/moveTo methods + * @bug 4313887 6838333 6917021 7006126 + * @summary Unit test for java.nio.file.Files copy and move methods * @library .. * @build CopyAndMove PassThroughFileSystem * @run main/othervm CopyAndMove @@ -31,6 +31,7 @@ import java.nio.ByteBuffer; import java.nio.file.*; +import static java.nio.file.Files.*; import static java.nio.file.StandardCopyOption.*; import static java.nio.file.LinkOption.*; import java.nio.file.attribute.*; @@ -44,9 +45,10 @@ public class CopyAndMove { public static void main(String[] args) throws Exception { Path dir1 = TestUtil.createTemporaryDirectory(); try { + // Same directory - doCopyTests(dir1, dir1, TestUtil.supportsLinks(dir1)); - doMoveTests(dir1, dir1, TestUtil.supportsLinks(dir1)); + testCopyFileToFile(dir1, dir1, TestUtil.supportsLinks(dir1)); + testMove(dir1, dir1, TestUtil.supportsLinks(dir1)); // Different directories. Use test.dir if possible as it might be // a different volume/file system and so improve test coverage. @@ -55,16 +57,20 @@ public class CopyAndMove { try { boolean testSymbolicLinks = TestUtil.supportsLinks(dir1) && TestUtil.supportsLinks(dir2); - doCopyTests(dir1, dir2, testSymbolicLinks); - doMoveTests(dir1, dir2, testSymbolicLinks); + testCopyFileToFile(dir1, dir2, testSymbolicLinks); + testMove(dir1, dir2, testSymbolicLinks); } finally { TestUtil.removeAll(dir2); } // Target is location associated with custom provider Path dir3 = PassThroughFileSystem.create().getPath(dir1.toString()); - doCopyTests(dir1, dir3, false); - doMoveTests(dir1, dir3, false); + testCopyFileToFile(dir1, dir3, false); + testMove(dir1, dir3, false); + + // Test copy(InputStream,Path) and copy(Path,OutputStream) + testCopyInputStreamToFile(); + testCopyFileToOuputStream(); } finally { TestUtil.removeAll(dir1); @@ -121,9 +127,9 @@ public class CopyAndMove { static Map readUserDefinedFileAttributes(Path file) throws IOException { - UserDefinedFileAttributeView view = file - .getFileAttributeView(UserDefinedFileAttributeView.class); - Map result = new HashMap(); + UserDefinedFileAttributeView view = + getFileAttributeView(file, UserDefinedFileAttributeView.class); + Map result = new HashMap<>(); for (String name: view.list()) { int size = view.size(name); ByteBuffer bb = ByteBuffer.allocate(size); @@ -148,15 +154,15 @@ public class CopyAndMove { // get file attributes of source file String os = System.getProperty("os.name"); if (os.equals("SunOS") || os.equals("Linux")) { - posixAttributes = Attributes.readPosixFileAttributes(source, NOFOLLOW_LINKS); + posixAttributes = readAttributes(source, PosixFileAttributes.class, NOFOLLOW_LINKS); basicAttributes = posixAttributes; } if (os.startsWith("Windows")) { - dosAttributes = Attributes.readDosFileAttributes(source, NOFOLLOW_LINKS); + dosAttributes = readAttributes(source, DosFileAttributes.class, NOFOLLOW_LINKS); basicAttributes = dosAttributes; } if (basicAttributes == null) - basicAttributes = Attributes.readBasicFileAttributes(source, NOFOLLOW_LINKS); + basicAttributes = readAttributes(source, BasicFileAttributes.class, NOFOLLOW_LINKS); // hash file contents if regular file int hash = (basicAttributes.isRegularFile()) ? computeHash(source) : 0; @@ -164,20 +170,21 @@ public class CopyAndMove { // record link target if symbolic link Path linkTarget = null; if (basicAttributes.isSymbolicLink()) - linkTarget = source.readSymbolicLink(); + linkTarget = readSymbolicLink(source); // read named attributes if available (and file is not a sym link) if (!basicAttributes.isSymbolicLink() && - source.getFileStore().supportsFileAttributeView("xattr")) + getFileStore(source).supportsFileAttributeView("xattr")) { namedAttributes = readUserDefinedFileAttributes(source); } // move file - source.moveTo(target, options); + Path result = move(source, target, options); + assertTrue(result == target); // verify source does not exist - assertTrue(source.notExists()); + assertTrue(notExists(source)); // verify file contents if (basicAttributes.isRegularFile()) { @@ -187,13 +194,13 @@ public class CopyAndMove { // verify link target if (basicAttributes.isSymbolicLink()) { - if (!target.readSymbolicLink().equals(linkTarget)) + if (!readSymbolicLink(target).equals(linkTarget)) throw new RuntimeException("Failed to verify move of symbolic link"); } // verify basic attributes checkBasicAttributes(basicAttributes, - Attributes.readBasicFileAttributes(target, NOFOLLOW_LINKS)); + readAttributes(target, BasicFileAttributes.class, NOFOLLOW_LINKS)); // verify other attributes when same provider if (source.getFileSystem().provider() == target.getFileSystem().provider()) { @@ -201,18 +208,19 @@ public class CopyAndMove { // verify POSIX attributes if (posixAttributes != null && !basicAttributes.isSymbolicLink()) { checkPosixAttributes(posixAttributes, - Attributes.readPosixFileAttributes(target, NOFOLLOW_LINKS)); + readAttributes(target, PosixFileAttributes.class, NOFOLLOW_LINKS)); } // verify DOS attributes if (dosAttributes != null && !basicAttributes.isSymbolicLink()) { - checkDosAttributes(dosAttributes, - Attributes.readDosFileAttributes(target, NOFOLLOW_LINKS)); + DosFileAttributes attrs = + readAttributes(target, DosFileAttributes.class, NOFOLLOW_LINKS); + checkDosAttributes(dosAttributes, attrs); } // verify named attributes if (namedAttributes != null && - target.getFileStore().supportsFileAttributeView("xattr")) + getFileStore(target).supportsFileAttributeView("xattr")) { checkUserDefinedFileAttributes(namedAttributes, readUserDefinedFileAttributes(target)); @@ -221,14 +229,14 @@ public class CopyAndMove { } /** - * Tests all possible ways to invoke moveTo + * Tests all possible ways to invoke move */ - static void doMoveTests(Path dir1, Path dir2, boolean supportsLinks) + static void testMove(Path dir1, Path dir2, boolean supportsLinks) throws IOException { Path source, target, entry; - boolean sameDevice = dir1.getFileStore().equals(dir2.getFileStore()); + boolean sameDevice = getFileStore(dir1).equals(getFileStore(dir2)); // -- regular file -- @@ -238,27 +246,28 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); moveAndVerify(source, target); - target.delete(); + delete(target); /** * Test: move regular file, target exists */ source = createSourceFile(dir1); - target = getTargetFile(dir2).createFile(); + target = getTargetFile(dir2); + createFile(target); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - target.delete(); - target.createDirectory(); + delete(target); + createDirectory(target); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: move regular file, target does not exist @@ -266,38 +275,42 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); /** * Test: move regular file, target exists */ source = createSourceFile(dir1); - target = getTargetFile(dir2).createFile(); + target = getTargetFile(dir2); + createFile(target); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); /** * Test: move regular file, target exists and is empty directory */ source = createSourceFile(dir1); - target = getTargetFile(dir2).createDirectory(); + target = getTargetFile(dir2); + createDirectory(target); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); /** * Test: move regular file, target exists and is non-empty directory */ source = createSourceFile(dir1); - target = getTargetFile(dir2).createDirectory(); - entry = target.resolve("foo").createFile(); + target = getTargetFile(dir2); + createDirectory(target); + entry = target.resolve("foo"); + createFile(entry); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - entry.delete(); - source.delete(); - target.delete(); + delete(entry); + delete(source); + delete(target); /** * Test atomic move of regular file (same file store) @@ -305,7 +318,7 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir1); moveAndVerify(source, target, ATOMIC_MOVE); - target.delete(); + delete(target); /** * Test atomic move of regular file (different file store) @@ -318,7 +331,7 @@ public class CopyAndMove { throw new RuntimeException("AtomicMoveNotSupportedException expected"); } catch (AtomicMoveNotSupportedException x) { } - source.delete(); + delete(source); } // -- directories -- @@ -329,27 +342,28 @@ public class CopyAndMove { source = createSourceDirectory(dir1); target = getTargetFile(dir2); moveAndVerify(source, target); - target.delete(); + delete(target); /** * Test: move empty directory, target exists */ source = createSourceDirectory(dir1); - target = getTargetFile(dir2).createFile(); + target = getTargetFile(dir2); + createFile(target); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - target.delete(); - target.createDirectory(); + delete(target); + createDirectory(target); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: move empty directory, target does not exist @@ -357,74 +371,78 @@ public class CopyAndMove { source = createSourceDirectory(dir1); target = getTargetFile(dir2); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); /** * Test: move empty directory, target exists */ source = createSourceDirectory(dir1); - target = getTargetFile(dir2).createFile(); + target = getTargetFile(dir2); + createFile(target); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); /** * Test: move empty, target exists and is empty directory */ source = createSourceDirectory(dir1); - target = getTargetFile(dir2).createDirectory(); + target = getTargetFile(dir2); + createDirectory(target); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); /** * Test: move empty directory, target exists and is non-empty directory */ source = createSourceDirectory(dir1); - target = getTargetFile(dir2).createDirectory(); - entry = target.resolve("foo").createFile(); + target = getTargetFile(dir2); + createDirectory(target); + entry = target.resolve("foo"); + createFile(entry); try { moveAndVerify(source, target, REPLACE_EXISTING); - throw new RuntimeException("FileAlreadyExistsException expected"); - } catch (FileAlreadyExistsException x) { + throw new RuntimeException("DirectoryNotEmptyException expected"); + } catch (DirectoryNotEmptyException x) { } - entry.delete(); - source.delete(); - target.delete(); + delete(entry); + delete(source); + delete(target); /** * Test: move non-empty directory (same file system) */ source = createSourceDirectory(dir1); - source.resolve("foo").createFile(); + createFile(source.resolve("foo")); target = getTargetFile(dir1); moveAndVerify(source, target); - target.resolve("foo").delete(); - target.delete(); + delete(target.resolve("foo")); + delete(target); /** * Test: move non-empty directory (different file store) */ if (!sameDevice) { source = createSourceDirectory(dir1); - source.resolve("foo").createFile(); + createFile(source.resolve("foo")); target = getTargetFile(dir2); try { moveAndVerify(source, target); throw new RuntimeException("IOException expected"); } catch (IOException x) { } - source.resolve("foo").delete(); - source.delete(); + delete(source.resolve("foo")); + delete(source); } /** * Test atomic move of directory (same file store) */ source = createSourceDirectory(dir1); - source.resolve("foo").createFile(); + createFile(source.resolve("foo")); target = getTargetFile(dir1); moveAndVerify(source, target, ATOMIC_MOVE); - target.resolve("foo").delete(); - target.delete(); + delete(target.resolve("foo")); + delete(target); // -- symbolic links -- @@ -433,21 +451,23 @@ public class CopyAndMove { */ if (supportsLinks) { Path tmp = createSourceFile(dir1); - source = dir1.resolve("link").createSymbolicLink(tmp); + source = dir1.resolve("link"); + createSymbolicLink(source, tmp); target = getTargetFile(dir2); moveAndVerify(source, target); - target.delete(); - tmp.delete(); + delete(target); + delete(tmp); } /** * Test: Move symbolic link to directory, target does not exist */ if (supportsLinks) { - source = dir1.resolve("link").createSymbolicLink(dir2); + source = dir1.resolve("link"); + createSymbolicLink(source, dir2); target = getTargetFile(dir2); moveAndVerify(source, target); - target.delete(); + delete(target); } /** @@ -455,72 +475,84 @@ public class CopyAndMove { */ if (supportsLinks) { Path tmp = Paths.get("doesnotexist"); - source = dir1.resolve("link").createSymbolicLink(tmp); + source = dir1.resolve("link"); + createSymbolicLink(source, tmp); target = getTargetFile(dir2); moveAndVerify(source, target); - target.delete(); + delete(target); } /** * Test: Move symbolic link, target exists */ if (supportsLinks) { - source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir2).createFile(); + source = dir1.resolve("link"); + createSymbolicLink(source, dir2); + target = getTargetFile(dir2); + createFile(target); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - source.delete(); - target.delete(); + delete(source); + delete(target); } /** * Test: Move regular file, target exists */ if (supportsLinks) { - source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir2).createFile(); + source = dir1.resolve("link"); + createSymbolicLink(source, dir2); + target = getTargetFile(dir2); + createFile(target); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); } /** * Test: move symbolic link, target exists and is empty directory */ if (supportsLinks) { - source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir2).createDirectory(); + source = dir1.resolve("link"); + createSymbolicLink(source, dir2); + target = getTargetFile(dir2); + createDirectory(target); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); } /** * Test: symbolic link, target exists and is non-empty directory */ if (supportsLinks) { - source = dir1.resolve("link").createSymbolicLink(dir2); - target = getTargetFile(dir2).createDirectory(); - entry = target.resolve("foo").createFile(); + source = dir1.resolve("link"); + createSymbolicLink(source, dir2); + target = getTargetFile(dir2); + createDirectory(target); + entry = target.resolve("foo"); + createFile(entry); try { moveAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - entry.delete(); - source.delete(); - target.delete(); + delete(entry); + delete(source); + delete(target); } /** * Test atomic move of symbolic link (same file store) */ if (supportsLinks) { - source = dir1.resolve("link").createSymbolicLink(dir1); - target = getTargetFile(dir2).createFile(); + source = dir1.resolve("link"); + createSymbolicLink(source, dir1); + target = getTargetFile(dir2); + createFile(target); moveAndVerify(source, target, REPLACE_EXISTING); - target.delete(); + delete(target); } // -- misc. tests -- @@ -531,19 +563,23 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); try { - source.moveTo(null); + move(null, target); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { - source.moveTo(target, (CopyOption[])null); + move(source, null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + try { + move(source, target, (CopyOption[])null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { CopyOption[] opts = { REPLACE_EXISTING, null }; - source.moveTo(target, opts); + move(source, target, opts); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } - source.delete(); + delete(source); /** * Test UOE @@ -551,19 +587,20 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); try { - source.moveTo(target, new CopyOption() { }); + move(source, target, new CopyOption() { }); } catch (UnsupportedOperationException x) { } try { - source.moveTo(target, REPLACE_EXISTING, new CopyOption() { }); + move(source, target, REPLACE_EXISTING, new CopyOption() { }); } catch (UnsupportedOperationException x) { } - source.delete(); + delete(source); } // copy source to target with verification static void copyAndVerify(Path source, Path target, CopyOption... options) throws IOException { - source.copyTo(target, options); + Path result = copy(source, target, options); + assertTrue(result == target); // get attributes of source and target file to verify copy boolean followLinks = true; @@ -577,8 +614,8 @@ public class CopyAndMove { if (opt == COPY_ATTRIBUTES) copyAttributes = true; } - BasicFileAttributes basicAttributes = Attributes - .readBasicFileAttributes(source, linkOptions); + BasicFileAttributes basicAttributes = + readAttributes(source, BasicFileAttributes.class, linkOptions); // check hash if regular file if (basicAttributes.isRegularFile()) @@ -586,12 +623,12 @@ public class CopyAndMove { // check link target if symbolic link if (basicAttributes.isSymbolicLink()) - assert( source.readSymbolicLink().equals(target.readSymbolicLink())); + assert(readSymbolicLink(source).equals(readSymbolicLink(target))); // check that attributes are copied if (copyAttributes && followLinks) { checkBasicAttributes(basicAttributes, - Attributes.readBasicFileAttributes(source, linkOptions)); + readAttributes(source, BasicFileAttributes.class, linkOptions)); // verify other attributes when same provider if (source.getFileSystem().provider() == target.getFileSystem().provider()) { @@ -600,21 +637,21 @@ public class CopyAndMove { String os = System.getProperty("os.name"); if (os.equals("SunOS") || os.equals("Linux")) { checkPosixAttributes( - Attributes.readPosixFileAttributes(source, linkOptions), - Attributes.readPosixFileAttributes(target, linkOptions)); + readAttributes(source, PosixFileAttributes.class, linkOptions), + readAttributes(target, PosixFileAttributes.class, linkOptions)); } // check DOS attributes are copied if (os.startsWith("Windows")) { checkDosAttributes( - Attributes.readDosFileAttributes(source, linkOptions), - Attributes.readDosFileAttributes(target, linkOptions)); + readAttributes(source, DosFileAttributes.class, linkOptions), + readAttributes(target, DosFileAttributes.class, linkOptions)); } // check named attributes are copied if (followLinks && - source.getFileStore().supportsFileAttributeView("xattr") && - target.getFileStore().supportsFileAttributeView("xattr")) + getFileStore(source).supportsFileAttributeView("xattr") && + getFileStore(target).supportsFileAttributeView("xattr")) { checkUserDefinedFileAttributes(readUserDefinedFileAttributes(source), readUserDefinedFileAttributes(target)); @@ -624,9 +661,9 @@ public class CopyAndMove { } /** - * Tests all possible ways to invoke copyTo + * Tests all possible ways to invoke copy to copy a file to a file */ - static void doCopyTests(Path dir1, Path dir2, boolean supportsLinks) + static void testCopyFileToFile(Path dir1, Path dir2, boolean supportsLinks) throws IOException { Path source, target, link, entry; @@ -639,28 +676,29 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); copyAndVerify(source, target); - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy regular file, target exists */ source = createSourceFile(dir1); - target = getTargetFile(dir2).createFile(); + target = getTargetFile(dir2); + createFile(target); try { copyAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - target.delete(); - target.createDirectory(); + delete(target); + createDirectory(target); try { copyAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy regular file, target does not exist @@ -668,41 +706,45 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); copyAndVerify(source, target, REPLACE_EXISTING); - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy regular file, target exists */ source = createSourceFile(dir1); - target = getTargetFile(dir2).createFile(); + target = getTargetFile(dir2); + createFile(target); copyAndVerify(source, target, REPLACE_EXISTING); - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy regular file, target exists and is empty directory */ source = createSourceFile(dir1); - target = getTargetFile(dir2).createDirectory(); + target = getTargetFile(dir2); + createDirectory(target); copyAndVerify(source, target, REPLACE_EXISTING); - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy regular file, target exists and is non-empty directory */ source = createSourceFile(dir1); - target = getTargetFile(dir2).createDirectory(); - entry = target.resolve("foo").createFile(); + target = getTargetFile(dir2); + createDirectory(target); + entry = target.resolve("foo"); + createFile(entry); try { copyAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - entry.delete(); - source.delete(); - target.delete(); + delete(entry); + delete(source); + delete(target); /** * Test: copy regular file + attributes @@ -710,8 +752,8 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); copyAndVerify(source, target, COPY_ATTRIBUTES); - source.delete(); - target.delete(); + delete(source); + delete(target); // -- directory -- @@ -722,28 +764,29 @@ public class CopyAndMove { source = createSourceDirectory(dir1); target = getTargetFile(dir2); copyAndVerify(source, target); - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy directory, target exists */ source = createSourceDirectory(dir1); - target = getTargetFile(dir2).createFile(); + target = getTargetFile(dir2); + createFile(target); try { copyAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - target.delete(); - target.createDirectory(); + delete(target); + createDirectory(target); try { copyAndVerify(source, target); throw new RuntimeException("FileAlreadyExistsException expected"); } catch (FileAlreadyExistsException x) { } - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy directory, target does not exist @@ -751,41 +794,45 @@ public class CopyAndMove { source = createSourceDirectory(dir1); target = getTargetFile(dir2); copyAndVerify(source, target, REPLACE_EXISTING); - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy directory, target exists */ source = createSourceDirectory(dir1); - target = getTargetFile(dir2).createFile(); + target = getTargetFile(dir2); + createFile(target); copyAndVerify(source, target, REPLACE_EXISTING); - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy directory, target exists and is empty directory */ source = createSourceDirectory(dir1); - target = getTargetFile(dir2).createDirectory(); + target = getTargetFile(dir2); + createDirectory(target); copyAndVerify(source, target, REPLACE_EXISTING); - source.delete(); - target.delete(); + delete(source); + delete(target); /** * Test: copy directory, target exists and is non-empty directory */ source = createSourceDirectory(dir1); - target = getTargetFile(dir2).createDirectory(); - entry = target.resolve("foo").createFile(); + target = getTargetFile(dir2); + createDirectory(target); + entry = target.resolve("foo"); + createFile(entry); try { copyAndVerify(source, target, REPLACE_EXISTING); - throw new RuntimeException("FileAlreadyExistsException expected"); - } catch (FileAlreadyExistsException x) { + throw new RuntimeException("DirectoryNotEmptyException expected"); + } catch (DirectoryNotEmptyException x) { } - entry.delete(); - source.delete(); - target.delete(); + delete(entry); + delete(source); + delete(target); /* * Test: copy directory + attributes @@ -793,8 +840,8 @@ public class CopyAndMove { source = createSourceDirectory(dir1); target = getTargetFile(dir2); copyAndVerify(source, target, COPY_ATTRIBUTES); - source.delete(); - target.delete(); + delete(source); + delete(target); // -- symbolic links -- @@ -803,11 +850,12 @@ public class CopyAndMove { */ if (supportsLinks) { source = createSourceFile(dir1); - link = dir1.resolve("link").createSymbolicLink(source); + link = dir1.resolve("link"); + createSymbolicLink(link, source); target = getTargetFile(dir2); copyAndVerify(link, target); - link.delete(); - source.delete(); + delete(link); + delete(source); } /** @@ -815,34 +863,38 @@ public class CopyAndMove { */ if (supportsLinks) { source = createSourceFile(dir1); - link = dir1.resolve("link").createSymbolicLink(source); + link = dir1.resolve("link"); + createSymbolicLink(link, source); target = getTargetFile(dir2); copyAndVerify(link, target, NOFOLLOW_LINKS); - link.delete(); - source.delete(); + delete(link); + delete(source); } /** * Test: Copy link (to directory) */ if (supportsLinks) { - source = dir1.resolve("mydir").createDirectory(); - link = dir1.resolve("link").createSymbolicLink(source); + source = dir1.resolve("mydir"); + createDirectory(source); + link = dir1.resolve("link"); + createSymbolicLink(link, source); target = getTargetFile(dir2); copyAndVerify(link, target, NOFOLLOW_LINKS); - link.delete(); - source.delete(); + delete(link); + delete(source); } /** * Test: Copy broken link */ if (supportsLinks) { - assertTrue(source.notExists()); - link = dir1.resolve("link").createSymbolicLink(source); + assertTrue(notExists(source)); + link = dir1.resolve("link"); + createSymbolicLink(link, source); target = getTargetFile(dir2); copyAndVerify(link, target, NOFOLLOW_LINKS); - link.delete(); + delete(link); } /** @@ -852,10 +904,11 @@ public class CopyAndMove { System.getProperty("os.name").startsWith("Windows")) { Path unc = Paths.get("\\\\rialto\\share\\file"); - link = dir1.resolve("link").createSymbolicLink(unc); + link = dir1.resolve("link"); + createSymbolicLink(link, unc); target = getTargetFile(dir2); copyAndVerify(link, target, NOFOLLOW_LINKS); - link.delete(); + delete(link); } // -- misc. tests -- @@ -866,19 +919,19 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); try { - source.copyTo(null); + copy(source, null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { - source.copyTo(target, (CopyOption[])null); + copy(source, target, (CopyOption[])null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { CopyOption[] opts = { REPLACE_EXISTING, null }; - source.copyTo(target, opts); + copy(source, target, opts); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } - source.delete(); + delete(source); /** * Test UOE @@ -886,14 +939,154 @@ public class CopyAndMove { source = createSourceFile(dir1); target = getTargetFile(dir2); try { - source.copyTo(target, new CopyOption() { }); + copy(source, target, new CopyOption() { }); } catch (UnsupportedOperationException x) { } try { - source.copyTo(target, REPLACE_EXISTING, new CopyOption() { }); + copy(source, target, REPLACE_EXISTING, new CopyOption() { }); } catch (UnsupportedOperationException x) { } - source.delete(); + delete(source); } + /** + * Test copy from an input stream to a file + */ + static void testCopyInputStreamToFile() throws IOException { + testCopyInputStreamToFile(0); + for (int i=0; i<100; i++) { + testCopyInputStreamToFile(rand.nextInt(32000)); + } + + // FileAlreadyExistsException + Path target = createTempFile("blah", null); + try { + InputStream in = new ByteArrayInputStream(new byte[0]); + try { + copy(in, target); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException ignore) { } + } finally { + delete(target); + } + Path tmpdir = createTempDirectory("blah"); + try { + if (TestUtil.supportsLinks(tmpdir)) { + Path link = createSymbolicLink(tmpdir.resolve("link"), + tmpdir.resolve("target")); + try { + InputStream in = new ByteArrayInputStream(new byte[0]); + try { + copy(in, link); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException ignore) { } + } finally { + delete(link); + } + } + } finally { + delete(tmpdir); + } + + + // nulls + try { + copy((InputStream)null, target); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + copy(new ByteArrayInputStream(new byte[0]), (Path)null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + } + + static void testCopyInputStreamToFile(int size) throws IOException { + Path tmpdir = createTempDirectory("blah"); + Path source = tmpdir.resolve("source"); + Path target = tmpdir.resolve("target"); + try { + boolean testReplaceExisting = rand.nextBoolean(); + + // create source file + byte[] b = new byte[size]; + rand.nextBytes(b); + write(source, b); + + // target file might already exist + if (testReplaceExisting && rand.nextBoolean()) { + write(target, new byte[rand.nextInt(512)]); + } + + // copy from stream to file + InputStream in = new FileInputStream(source.toFile()); + try { + long n; + if (testReplaceExisting) { + n = copy(in, target, StandardCopyOption.REPLACE_EXISTING); + } else { + n = copy(in, target); + } + assertTrue(in.read() == -1); // EOF + assertTrue(n == size); + assertTrue(size(target) == size); + } finally { + in.close(); + } + + // check file + byte[] read = readAllBytes(target); + assertTrue(Arrays.equals(read, b)); + + } finally { + deleteIfExists(source); + deleteIfExists(target); + delete(tmpdir); + } + } + + /** + * Test copy from file to output stream + */ + static void testCopyFileToOuputStream() throws IOException { + testCopyFileToOuputStream(0); + for (int i=0; i<100; i++) { + testCopyFileToOuputStream(rand.nextInt(32000)); + } + + // nulls + try { + copy((Path)null, new ByteArrayOutputStream()); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + Path source = createTempFile("blah", null); + delete(source); + copy(source, (OutputStream)null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + } + + static void testCopyFileToOuputStream(int size) throws IOException { + Path source = createTempFile("blah", null); + try { + byte[] b = new byte[size]; + rand.nextBytes(b); + write(source, b); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + long n = copy(source, out); + assertTrue(n == size); + assertTrue(out.size() == size); + + byte[] read = out.toByteArray(); + assertTrue(Arrays.equals(read, b)); + + // check output stream is open + out.write(0); + assertTrue(out.size() == size+1); + } finally { + delete(source); + } + } static void assertTrue(boolean value) { if (!value) @@ -904,8 +1097,7 @@ public class CopyAndMove { static int computeHash(Path file) throws IOException { int h = 0; - InputStream in = file.newInputStream(); - try { + try (InputStream in = newInputStream(file)) { byte[] buf = new byte[1024]; int n; do { @@ -914,8 +1106,6 @@ public class CopyAndMove { h = 31*h + (buf[i] & 0xff); } } while (n > 0); - } finally { - in.close(); } return h; } @@ -923,14 +1113,12 @@ public class CopyAndMove { // create file of random size in given directory static Path createSourceFile(Path dir) throws IOException { String name = "source" + Integer.toString(rand.nextInt()); - Path file = dir.resolve(name).createFile(); + Path file = dir.resolve(name); + createFile(file); byte[] bytes = new byte[rand.nextInt(128*1024)]; rand.nextBytes(bytes); - OutputStream out = file.newOutputStream(); - try { + try (OutputStream out = newOutputStream(file)) { out.write(bytes); - } finally { - out.close(); } randomizeAttributes(file); return file; @@ -939,7 +1127,8 @@ public class CopyAndMove { // create directory in the given directory static Path createSourceDirectory(Path dir) throws IOException { String name = "sourcedir" + Integer.toString(rand.nextInt()); - Path subdir = dir.resolve(name).createDirectory(); + Path subdir = dir.resolve(name); + createDirectory(subdir); randomizeAttributes(subdir); return subdir; } @@ -949,12 +1138,11 @@ public class CopyAndMove { String os = System.getProperty("os.name"); boolean isWindows = os.startsWith("Windows"); boolean isUnix = os.equals("SunOS") || os.equals("Linux"); - boolean isDirectory = Attributes.readBasicFileAttributes(file, NOFOLLOW_LINKS) - .isDirectory(); + boolean isDirectory = isDirectory(file, NOFOLLOW_LINKS); if (isUnix) { - Set perms = Attributes - .readPosixFileAttributes(file, NOFOLLOW_LINKS).permissions(); + Set perms = + getPosixFilePermissions(file, NOFOLLOW_LINKS); PosixFilePermission[] toChange = { PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_WRITE, @@ -970,25 +1158,25 @@ public class CopyAndMove { perms.remove(perm); } } - Attributes.setPosixFilePermissions(file, perms); + setPosixFilePermissions(file, perms); } if (isWindows) { - DosFileAttributeView view = file - .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS); + DosFileAttributeView view = + getFileAttributeView(file, DosFileAttributeView.class, NOFOLLOW_LINKS); // only set or unset the hidden attribute view.setHidden(heads()); } boolean addUserDefinedFileAttributes = heads() && - file.getFileStore().supportsFileAttributeView("xattr"); + getFileStore(file).supportsFileAttributeView("xattr"); // remove this when copying a direcory copies its named streams if (isWindows && isDirectory) addUserDefinedFileAttributes = false; if (addUserDefinedFileAttributes) { - UserDefinedFileAttributeView view = file - .getFileAttributeView(UserDefinedFileAttributeView.class); + UserDefinedFileAttributeView view = + getFileAttributeView(file, UserDefinedFileAttributeView.class); int n = rand.nextInt(16); while (n > 0) { byte[] value = new byte[1 + rand.nextInt(100)]; diff --git a/test/java/nio/file/Path/DeleteOnClose.java b/test/java/nio/file/Files/DeleteOnClose.java similarity index 73% rename from test/java/nio/file/Path/DeleteOnClose.java rename to test/java/nio/file/Files/DeleteOnClose.java index 506c848f6270e6e1039cbc7f15c178e6c1841e7c..9b50a30b0be07cbaa9accc1fc5742c55e265c9a4 100644 --- a/test/java/nio/file/Path/DeleteOnClose.java +++ b/test/java/nio/file/Files/DeleteOnClose.java @@ -31,44 +31,43 @@ public class DeleteOnClose { public static void main(String[] args) throws IOException { // open file but do not close it. Its existance will be checked by // the calling script. - Paths.get(args[0]).newByteChannel(READ, WRITE, DELETE_ON_CLOSE); + Files.newByteChannel(Paths.get(args[0]), READ, WRITE, DELETE_ON_CLOSE); // check temporary file has been deleted after closing it - Path file = File.createTempFile("blah", "tmp").toPath(); - file.newByteChannel(READ, WRITE, DELETE_ON_CLOSE).close(); - if (file.exists()) + Path file = Files.createTempFile("blah", "tmp"); + Files.newByteChannel(file, READ, WRITE, DELETE_ON_CLOSE).close(); + if (Files.exists(file)) throw new RuntimeException("Temporary file was not deleted"); - Path dir = TestUtil.createTemporaryDirectory(); + Path dir = Files.createTempDirectory("blah"); try { // check that DELETE_ON_CLOSE fails when file is a sym link if (TestUtil.supportsLinks(dir)) { - file = dir.resolve("foo").createFile(); - Path link = dir.resolve("link").createSymbolicLink(file); + file = dir.resolve("foo"); + Files.createFile(file); + Path link = dir.resolve("link"); + Files.createSymbolicLink(link, file); try { - link.newByteChannel(READ, WRITE, DELETE_ON_CLOSE); + Files.newByteChannel(link, READ, WRITE, DELETE_ON_CLOSE); throw new RuntimeException("IOException expected"); } catch (IOException ignore) { } } // check that DELETE_ON_CLOSE works with files created via open // directories - DirectoryStream stream = dir.newDirectoryStream(); - try { + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { if (stream instanceof SecureDirectoryStream) { - SecureDirectoryStream secure = (SecureDirectoryStream)stream; + SecureDirectoryStream secure = (SecureDirectoryStream)stream; file = Paths.get("foo"); - Set opts = new HashSet(); + Set opts = new HashSet<>(); opts.add(WRITE); opts.add(DELETE_ON_CLOSE); secure.newByteChannel(file, opts).close(); - if (dir.resolve(file).exists()) + if (Files.exists(dir.resolve(file))) throw new RuntimeException("File not deleted"); } - } finally { - stream.close(); } } finally { TestUtil.removeAll(dir); diff --git a/test/java/nio/file/Path/FileAttributes.java b/test/java/nio/file/Files/FileAttributes.java similarity index 51% rename from test/java/nio/file/Path/FileAttributes.java rename to test/java/nio/file/Files/FileAttributes.java index 5300beb77f54904ad04c2269e4a329b01dd69d1f..bd799dc6b1e71fcdc1d1c569c2441f530e7923b8 100644 --- a/test/java/nio/file/Path/FileAttributes.java +++ b/test/java/nio/file/Files/FileAttributes.java @@ -23,7 +23,7 @@ /* @test * @bug 4313887 6838333 - * @summary Unit test for java.nio.file.Path + * @summary Unit test for java.nio.file.Files * @library .. */ @@ -59,43 +59,43 @@ public class FileAttributes { } // Exercise getAttribute/setAttribute/readAttributes on basic attributes - static void checkBasicAttributes(FileRef file, BasicFileAttributes attrs) + static void checkBasicAttributes(Path file, BasicFileAttributes attrs) throws IOException { // getAttribute - checkEqual(attrs.size(), file.getAttribute("size")); - checkEqual(attrs.lastModifiedTime(), file.getAttribute("basic:lastModifiedTime")); - checkEqual(attrs.lastAccessTime(), file.getAttribute("lastAccessTime")); - checkEqual(attrs.creationTime(), file.getAttribute("basic:creationTime")); - assertTrue((Boolean)file.getAttribute("isRegularFile")); - assertTrue(!(Boolean)file.getAttribute("basic:isDirectory")); - assertTrue(!(Boolean)file.getAttribute("isSymbolicLink")); - assertTrue(!(Boolean)file.getAttribute("basic:isOther")); - checkEqual(attrs.fileKey(), file.getAttribute("basic:fileKey")); + checkEqual(attrs.size(), Files.getAttribute(file, "size")); + checkEqual(attrs.lastModifiedTime(), Files.getAttribute(file, "basic:lastModifiedTime")); + checkEqual(attrs.lastAccessTime(), Files.getAttribute(file, "lastAccessTime")); + checkEqual(attrs.creationTime(), Files.getAttribute(file, "basic:creationTime")); + assertTrue((Boolean)Files.getAttribute(file, "isRegularFile")); + assertTrue(!(Boolean)Files.getAttribute(file, "basic:isDirectory")); + assertTrue(!(Boolean)Files.getAttribute(file, "isSymbolicLink")); + assertTrue(!(Boolean)Files.getAttribute(file, "basic:isOther")); + checkEqual(attrs.fileKey(), Files.getAttribute(file, "basic:fileKey")); // setAttribute FileTime modTime = attrs.lastModifiedTime(); - file.setAttribute("basic:lastModifiedTime", FileTime.fromMillis(0L)); - checkEqual(Attributes.readBasicFileAttributes(file).lastModifiedTime(), + Files.setAttribute(file, "basic:lastModifiedTime", FileTime.fromMillis(0L)); + checkEqual(Files.getLastModifiedTime(file), FileTime.fromMillis(0L)); - file.setAttribute("lastModifiedTime", modTime); - checkEqual(Attributes.readBasicFileAttributes(file).lastModifiedTime(), modTime); + Files.setAttribute(file, "lastModifiedTime", modTime); + checkEqual(Files.getLastModifiedTime(file), modTime); - Map map; - map = file.readAttributes("*"); + Map map; + map = Files.readAttributes(file, "*"); assertTrue(map.size() >= 9); checkEqual(attrs.isRegularFile(), map.get("isRegularFile")); // check one - map = file.readAttributes("basic:*"); + map = Files.readAttributes(file, "basic:*"); assertTrue(map.size() >= 9); checkEqual(attrs.lastAccessTime(), map.get("lastAccessTime")); // check one - map = file.readAttributes("size,lastModifiedTime"); + map = Files.readAttributes(file, "size,lastModifiedTime"); assertTrue(map.size() == 2); checkEqual(attrs.size(), map.get("size")); checkEqual(attrs.lastModifiedTime(), map.get("lastModifiedTime")); - map = file.readAttributes( + map = Files.readAttributes(file, "basic:lastModifiedTime,lastAccessTime,ShouldNotExist"); assertTrue(map.size() == 2); checkEqual(attrs.lastModifiedTime(), map.get("lastModifiedTime")); @@ -103,110 +103,110 @@ public class FileAttributes { } // Exercise getAttribute/setAttribute/readAttributes on posix attributes - static void checkPosixAttributes(FileRef file, PosixFileAttributes attrs) + static void checkPosixAttributes(Path file, PosixFileAttributes attrs) throws IOException { checkBasicAttributes(file, attrs); // getAttribute - checkEqual(attrs.permissions(), file.getAttribute("posix:permissions")); - checkEqual(attrs.owner(), file.getAttribute("posix:owner")); - checkEqual(attrs.group(), file.getAttribute("posix:group")); + checkEqual(attrs.permissions(), Files.getAttribute(file, "posix:permissions")); + checkEqual(attrs.owner(), Files.getAttribute(file, "posix:owner")); + checkEqual(attrs.group(), Files.getAttribute(file, "posix:group")); // setAttribute Set orig = attrs.permissions(); - Set newPerms = new HashSet(orig); + Set newPerms = new HashSet<>(orig); newPerms.remove(PosixFilePermission.OTHERS_READ); newPerms.remove(PosixFilePermission.OTHERS_WRITE); newPerms.remove(PosixFilePermission.OTHERS_EXECUTE); - file.setAttribute("posix:permissions", newPerms); - checkEqual(Attributes.readPosixFileAttributes(file).permissions(), newPerms); - file.setAttribute("posix:permissions", orig); - checkEqual(Attributes.readPosixFileAttributes(file).permissions(), orig); - file.setAttribute("posix:owner", attrs.owner()); - file.setAttribute("posix:group", attrs.group()); + Files.setAttribute(file, "posix:permissions", newPerms); + checkEqual(Files.getPosixFilePermissions(file), newPerms); + Files.setAttribute(file, "posix:permissions", orig); + checkEqual(Files.getPosixFilePermissions(file), orig); + Files.setAttribute(file, "posix:owner", attrs.owner()); + Files.setAttribute(file, "posix:group", attrs.group()); // readAttributes - Map map; - map = file.readAttributes("posix:*"); + Map map; + map = Files.readAttributes(file, "posix:*"); assertTrue(map.size() >= 12); checkEqual(attrs.permissions(), map.get("permissions")); // check one - map = file.readAttributes("posix:size,owner,ShouldNotExist"); + map = Files.readAttributes(file, "posix:size,owner,ShouldNotExist"); assertTrue(map.size() == 2); checkEqual(attrs.size(), map.get("size")); checkEqual(attrs.owner(), map.get("owner")); } // Exercise getAttribute/readAttributes on unix attributes - static void checkUnixAttributes(FileRef file) throws IOException { + static void checkUnixAttributes(Path file) throws IOException { // getAttribute - int mode = (Integer)file.getAttribute("unix:mode"); - long ino = (Long)file.getAttribute("unix:ino"); - long dev = (Long)file.getAttribute("unix:dev"); - long rdev = (Long)file.getAttribute("unix:rdev"); - int nlink = (Integer)file.getAttribute("unix:nlink"); - int uid = (Integer)file.getAttribute("unix:uid"); - int gid = (Integer)file.getAttribute("unix:gid"); - FileTime ctime = (FileTime)file.getAttribute("unix:ctime"); + int mode = (Integer)Files.getAttribute(file, "unix:mode"); + long ino = (Long)Files.getAttribute(file, "unix:ino"); + long dev = (Long)Files.getAttribute(file, "unix:dev"); + long rdev = (Long)Files.getAttribute(file, "unix:rdev"); + int nlink = (Integer)Files.getAttribute(file, "unix:nlink"); + int uid = (Integer)Files.getAttribute(file, "unix:uid"); + int gid = (Integer)Files.getAttribute(file, "unix:gid"); + FileTime ctime = (FileTime)Files.getAttribute(file, "unix:ctime"); // readAttributes - Map map; - map = file.readAttributes("unix:*"); + Map map; + map = Files.readAttributes(file, "unix:*"); assertTrue(map.size() >= 20); - map = file.readAttributes("unix:size,uid,gid,ShouldNotExist"); + map = Files.readAttributes(file, "unix:size,uid,gid,ShouldNotExist"); assertTrue(map.size() == 3); checkEqual(map.get("size"), - Attributes.readBasicFileAttributes(file).size()); + Files.readAttributes(file, BasicFileAttributes.class).size()); } // Exercise getAttribute/setAttribute on dos attributes - static void checkDosAttributes(FileRef file, DosFileAttributes attrs) + static void checkDosAttributes(Path file, DosFileAttributes attrs) throws IOException { checkBasicAttributes(file, attrs); // getAttribute - checkEqual(attrs.isReadOnly(), file.getAttribute("dos:readonly")); - checkEqual(attrs.isHidden(), file.getAttribute("dos:hidden")); - checkEqual(attrs.isSystem(), file.getAttribute("dos:system")); - checkEqual(attrs.isArchive(), file.getAttribute("dos:archive")); + checkEqual(attrs.isReadOnly(), Files.getAttribute(file, "dos:readonly")); + checkEqual(attrs.isHidden(), Files.getAttribute(file, "dos:hidden")); + checkEqual(attrs.isSystem(), Files.getAttribute(file, "dos:system")); + checkEqual(attrs.isArchive(), Files.getAttribute(file, "dos:archive")); // setAttribute boolean value; value = attrs.isReadOnly(); - file.setAttribute("dos:readonly", !value); - checkEqual(Attributes.readDosFileAttributes(file).isReadOnly(), !value); - file.setAttribute("dos:readonly", value); - checkEqual(Attributes.readDosFileAttributes(file).isReadOnly(), value); + Files.setAttribute(file, "dos:readonly", !value); + checkEqual(Files.readAttributes(file, DosFileAttributes.class).isReadOnly(), !value); + Files.setAttribute(file, "dos:readonly", value); + checkEqual(Files.readAttributes(file, DosFileAttributes.class).isReadOnly(), value); value = attrs.isHidden(); - file.setAttribute("dos:hidden", !value); - checkEqual(Attributes.readDosFileAttributes(file).isHidden(), !value); - file.setAttribute("dos:hidden", value); - checkEqual(Attributes.readDosFileAttributes(file).isHidden(), value); + Files.setAttribute(file, "dos:hidden", !value); + checkEqual(Files.readAttributes(file, DosFileAttributes.class).isHidden(), !value); + Files.setAttribute(file, "dos:hidden", value); + checkEqual(Files.readAttributes(file, DosFileAttributes.class).isHidden(), value); value = attrs.isSystem(); - file.setAttribute("dos:system", !value); - checkEqual(Attributes.readDosFileAttributes(file).isSystem(), !value); - file.setAttribute("dos:system", value); - checkEqual(Attributes.readDosFileAttributes(file).isSystem(), value); + Files.setAttribute(file, "dos:system", !value); + checkEqual(Files.readAttributes(file, DosFileAttributes.class).isSystem(), !value); + Files.setAttribute(file, "dos:system", value); + checkEqual(Files.readAttributes(file, DosFileAttributes.class).isSystem(), value); value = attrs.isArchive(); - file.setAttribute("dos:archive", !value); - checkEqual(Attributes.readDosFileAttributes(file).isArchive(), !value); - file.setAttribute("dos:archive", value); - checkEqual(Attributes.readDosFileAttributes(file).isArchive(), value); + Files.setAttribute(file, "dos:archive", !value); + checkEqual(Files.readAttributes(file, DosFileAttributes.class).isArchive(), !value); + Files.setAttribute(file, "dos:archive", value); + checkEqual(Files.readAttributes(file, DosFileAttributes.class).isArchive(), value); // readAttributes - Map map; - map = file.readAttributes("dos:*"); + Map map; + map = Files.readAttributes(file, "dos:*"); assertTrue(map.size() >= 13); checkEqual(attrs.isReadOnly(), map.get("readonly")); // check one - map = file.readAttributes("dos:size,hidden,ShouldNotExist"); + map = Files.readAttributes(file, "dos:size,hidden,ShouldNotExist"); assertTrue(map.size() == 2); checkEqual(attrs.size(), map.get("size")); checkEqual(attrs.isHidden(), map.get("hidden")); @@ -215,40 +215,41 @@ public class FileAttributes { static void miscTests(Path file) throws IOException { // NPE tests try { - file.getAttribute(null); + Files.getAttribute(file, null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException npe) { } try { - file.getAttribute("isRegularFile", (LinkOption[])null); + Files.getAttribute(file, "isRegularFile", (LinkOption[])null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException npe) { } try { - file.setAttribute(null, 0L); + Files.setAttribute(file, null, 0L); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException npe) { } } static void doTests(Path dir) throws IOException { - Path file = dir.resolve("foo").createFile(); - FileStore store = file.getFileStore(); + Path file = dir.resolve("foo"); + Files.createFile(file); + FileStore store = Files.getFileStore(file); try { checkBasicAttributes(file, - Attributes.readBasicFileAttributes(file)); + Files.readAttributes(file, BasicFileAttributes.class)); if (store.supportsFileAttributeView("posix")) checkPosixAttributes(file, - Attributes.readPosixFileAttributes(file)); + Files.readAttributes(file, PosixFileAttributes.class)); if (store.supportsFileAttributeView("unix")) checkUnixAttributes(file); if (store.supportsFileAttributeView("dos")) checkDosAttributes(file, - Attributes.readDosFileAttributes(file)); + Files.readAttributes(file, DosFileAttributes.class)); miscTests(file); } finally { - file.delete(); + Files.delete(file); } } diff --git a/test/java/nio/file/Path/InterruptCopy.java b/test/java/nio/file/Files/InterruptCopy.java similarity index 90% rename from test/java/nio/file/Path/InterruptCopy.java rename to test/java/nio/file/Files/InterruptCopy.java index 11be5a2e198e924069f7e1cc4f72e05041fa2462..1502d9e824e5a99ac233b3fc7fc11c749aff50b0 100644 --- a/test/java/nio/file/Path/InterruptCopy.java +++ b/test/java/nio/file/Files/InterruptCopy.java @@ -29,7 +29,6 @@ */ import java.nio.file.*; -import java.nio.file.attribute.Attributes; import java.io.*; import java.util.concurrent.*; import com.sun.nio.file.ExtendedCopyOption; @@ -43,10 +42,9 @@ public class InterruptCopy { public static void main(String[] args) throws Exception { Path dir = TestUtil.createTemporaryDirectory(); try { - FileStore store = dir.getFileStore(); + FileStore store = Files.getFileStore(dir); System.out.format("Checking space (%s)\n", store); - long usableSpace = Attributes - .readFileStoreSpaceAttributes(store).usableSpace(); + long usableSpace = store.getUsableSpace(); if (usableSpace < 2*FILE_SIZE_TO_COPY) { System.out.println("Insufficient disk space to run test."); return; @@ -66,14 +64,11 @@ public class InterruptCopy { System.out.println("Creating source file..."); byte[] buf = new byte[32*1024]; long total = 0; - OutputStream out = source.newOutputStream(); - try { + try (OutputStream out = Files.newOutputStream(source)) { do { out.write(buf); total += buf.length; } while (total < FILE_SIZE_TO_COPY); - } finally { - out.close(); } System.out.println("Source file created."); @@ -89,7 +84,7 @@ public class InterruptCopy { System.out.println("Copying file..."); try { long start = System.currentTimeMillis(); - source.copyTo(target, ExtendedCopyOption.INTERRUPTIBLE); + Files.copy(source, target, ExtendedCopyOption.INTERRUPTIBLE); long duration = System.currentTimeMillis() - start; if (duration > DURATION_MAX_IN_MS) throw new RuntimeException("Copy was not interrupted"); @@ -109,7 +104,7 @@ public class InterruptCopy { Future result = pool.submit(new Callable() { public Void call() throws IOException { System.out.println("Copying file..."); - source.copyTo(target, ExtendedCopyOption.INTERRUPTIBLE, + Files.copy(source, target, ExtendedCopyOption.INTERRUPTIBLE, StandardCopyOption.REPLACE_EXISTING); return null; } diff --git a/test/java/nio/file/Path/Links.java b/test/java/nio/file/Files/Links.java similarity index 72% rename from test/java/nio/file/Path/Links.java rename to test/java/nio/file/Files/Links.java index ced18e1cd288c49bbb85d1545907e7797e86ca41..0c19a0c92b528eaf039bacb57de672036e83fb3b 100644 --- a/test/java/nio/file/Path/Links.java +++ b/test/java/nio/file/Files/Links.java @@ -23,7 +23,7 @@ /* @test * @bug 4313887 6838333 6863864 - * @summary Unit test for java.nio.file.Path createSymbolicLink, + * @summary Unit test for java.nio.file.Files createSymbolicLink, * readSymbolicLink, and createLink methods * @library .. * @build Links @@ -52,8 +52,8 @@ public class Links { // Check if sym links are supported try { - link.createSymbolicLink(Paths.get("foo")); - link.delete(); + Files.createSymbolicLink(link, Paths.get("foo")); + Files.delete(link); } catch (UnsupportedOperationException x) { // sym links not supported return; @@ -70,11 +70,11 @@ public class Links { String[] targets = (isWindows) ? windowsTargets : otherTargets; for (String s: targets) { Path target = Paths.get(s); - link.createSymbolicLink(target); + Files.createSymbolicLink(link, target); try { - assertTrue(link.readSymbolicLink().equals(target)); + assertTrue(Files.readSymbolicLink(link).equals(target)); } finally { - link.delete(); + Files.delete(link); } } @@ -82,57 +82,54 @@ public class Links { Path mydir = dir.resolve("mydir"); Path myfile = mydir.resolve("myfile"); try { - mydir.createDirectory(); - myfile.createFile(); + Files.createDirectory(mydir); + Files.createFile(myfile); // link -> "mydir" - link.createSymbolicLink(mydir.getName()); - assertTrue(link.readSymbolicLink().equals(mydir.getName())); + Files.createSymbolicLink(link, mydir.getFileName()); + assertTrue(Files.readSymbolicLink(link).equals(mydir.getFileName())); // Test access to directory via link - DirectoryStream stream = link.newDirectoryStream(); - try { + try (DirectoryStream stream = Files.newDirectoryStream(link)) { boolean found = false; for (Path entry: stream) { - if (entry.getName().equals(myfile.getName())) { + if (entry.getFileName().equals(myfile.getFileName())) { found = true; break; } } assertTrue(found); - } finally { - stream.close(); } // Test link2 -> link -> mydir final Path link2 = dir.resolve("link2"); - Path target2 = link.getName(); - link2.createSymbolicLink(target2); + Path target2 = link.getFileName(); + Files.createSymbolicLink(link2, target2); try { - assertTrue(link2.readSymbolicLink().equals(target2)); - link2.newDirectoryStream().close(); + assertTrue(Files.readSymbolicLink(link2).equals(target2)); + Files.newDirectoryStream(link2).close(); } finally { - link2.delete(); + Files.delete(link2); } // Remove mydir and re-create link2 before re-creating mydir // (This is a useful test on Windows to ensure that creating a // sym link to a directory sym link creates the right type of link). - myfile.delete(); - mydir.delete(); - link2.createSymbolicLink(target2); + Files.delete(myfile); + Files.delete(mydir); + Files.createSymbolicLink(link2, target2); try { - assertTrue(link2.readSymbolicLink().equals(target2)); - mydir.createDirectory(); - link2.newDirectoryStream().close(); + assertTrue(Files.readSymbolicLink(link2).equals(target2)); + Files.createDirectory(mydir); + Files.newDirectoryStream(link2).close(); } finally { - link2.delete(); + Files.delete(link2); } } finally { - myfile.deleteIfExists(); - mydir.deleteIfExists(); - link.deleteIfExists(); + Files.deleteIfExists(myfile); + Files.deleteIfExists(mydir); + Files.deleteIfExists(link); } } @@ -140,11 +137,12 @@ public class Links { * Exercise createLink method */ static void testHardLinks(Path dir) throws IOException { - Path foo = dir.resolve("foo").createFile(); + Path foo = dir.resolve("foo"); + Files.createFile(foo); try { - Path bar; + Path bar = dir.resolve("bar"); try { - bar = dir.resolve("bar").createLink(foo); + Files.createLink(bar, foo); } catch (UnsupportedOperationException x) { return; } catch (IOException x) { @@ -152,18 +150,16 @@ public class Links { return; } try { - Object key1 = Attributes - .readBasicFileAttributes(foo).fileKey(); - Object key2 = Attributes - .readBasicFileAttributes(bar).fileKey(); + Object key1 = Files.readAttributes(foo, BasicFileAttributes.class).fileKey(); + Object key2 = Files.readAttributes(bar, BasicFileAttributes.class).fileKey(); assertTrue((key1 == null) || (key1.equals(key2))); } finally { - bar.delete(); + Files.delete(bar); } } finally { - foo.delete(); + Files.delete(foo); } } diff --git a/test/java/nio/file/Files/Misc.java b/test/java/nio/file/Files/Misc.java index 621b95981ff06f92565a14b14280dab256263fef..1ff9d0af1903e5a321930bad4b43c72f34c4c7b7 100644 --- a/test/java/nio/file/Files/Misc.java +++ b/test/java/nio/file/Files/Misc.java @@ -22,122 +22,335 @@ */ /* @test - * @bug 4313887 6838333 6865748 - * @summary Unit test for java.nio.file.Files for miscellenous cases not - * covered by other tests + * @bug 4313887 6838333 + * @summary Unit test for miscellenous methods in java.nio.file.Files * @library .. */ import java.nio.file.*; -import java.nio.file.attribute.Attributes; -import java.nio.file.attribute.BasicFileAttributes; +import static java.nio.file.Files.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; import java.io.IOException; import java.util.*; public class Misc { - static void npeExpected() { - throw new RuntimeException("NullPointerException expected"); + public static void main(String[] args) throws IOException { + Path dir = TestUtil.createTemporaryDirectory(); + try { + testCreateDirectories(dir); + testIsHidden(dir); + testIsSameFile(dir); + testFileTypeMethods(dir); + testAccessMethods(dir); + } finally { + TestUtil.removeAll(dir); + } } - public static void main(String[] args) throws IOException { + /** + * Tests createDirectories + */ + static void testCreateDirectories(Path tmpdir) throws IOException { + // a no-op + createDirectories(tmpdir); - // -- Files.createDirectories -- + // create one directory + Path subdir = tmpdir.resolve("a"); + createDirectories(subdir); + assertTrue(exists(subdir)); - Path dir = TestUtil.createTemporaryDirectory(); + // create parents + subdir = subdir.resolve("b/c/d"); + createDirectories(subdir); + assertTrue(exists(subdir)); + + // existing file is not a directory + Path file = createFile(tmpdir.resolve("x")); try { - // no-op - Files.createDirectories(dir); - - // create one directory - Path subdir = dir.resolve("a"); - Files.createDirectories(subdir); - if (!subdir.exists()) - throw new RuntimeException("directory not created"); - - // create parents - subdir = subdir.resolve("b/c/d"); - Files.createDirectories(subdir); - if (!subdir.exists()) - throw new RuntimeException("directory not created"); - - // existing file is not a directory - Path file = dir.resolve("x").createFile(); - try { - Files.createDirectories(file); - throw new RuntimeException("failure expected"); - } catch (FileAlreadyExistsException x) { } - try { - Files.createDirectories(file.resolve("y")); - throw new RuntimeException("failure expected"); - } catch (IOException x) { } + createDirectories(file); + throw new RuntimeException("failure expected"); + } catch (FileAlreadyExistsException x) { } + try { + createDirectories(file.resolve("y")); + throw new RuntimeException("failure expected"); + } catch (IOException x) { } + } - } finally { - TestUtil.removeAll(dir); + /** + * Tests isHidden + */ + static void testIsHidden(Path tmpdir) throws IOException { + assertTrue(!isHidden(tmpdir)); + + Path file = tmpdir.resolve(".foo"); + if (System.getProperty("os.name").startsWith("Windows")) { + createFile(file); + try { + setAttribute(file, "dos:hidden", true); + try { + assertTrue(isHidden(file)); + } finally { + setAttribute(file, "dos:hidden", false); + } + } finally { + delete(file); + } + } else { + assertTrue(isHidden(file)); } + } - // --- NullPointerException -- + /** + * Tests isSameFile + */ + static void testIsSameFile(Path tmpdir) throws IOException { + Path thisFile = tmpdir.resolve("thisFile"); + Path thatFile = tmpdir.resolve("thatFile"); + /** + * Test: isSameFile for self + */ + assertTrue(isSameFile(thisFile, thisFile)); + + /** + * Test: Neither files exist + */ try { - Files.probeContentType(null); - npeExpected(); - } catch (NullPointerException e) { + isSameFile(thisFile, thatFile); + throw new RuntimeException("IOException not thrown"); + } catch (IOException x) { } try { - Files.walkFileTree(null, EnumSet.noneOf(FileVisitOption.class), - Integer.MAX_VALUE, new SimpleFileVisitor(){}); - npeExpected(); - } catch (NullPointerException e) { + isSameFile(thatFile, thisFile); + throw new RuntimeException("IOException not thrown"); + } catch (IOException x) { } + + createFile(thisFile); try { - Files.walkFileTree(Paths.get("."), null, Integer.MAX_VALUE, - new SimpleFileVisitor(){}); - npeExpected(); - } catch (NullPointerException e) { + /** + * Test: One file exists + */ + try { + isSameFile(thisFile, thatFile); + throw new RuntimeException("IOException not thrown"); + } catch (IOException x) { + } + try { + isSameFile(thatFile, thisFile); + throw new RuntimeException("IOException not thrown"); + } catch (IOException x) { + } + + /** + * Test: Both file exists + */ + createFile(thatFile); + try { + assertTrue(!isSameFile(thisFile, thatFile)); + assertTrue(!isSameFile(thatFile, thisFile)); + } finally { + delete(thatFile); + } + + /** + * Test: Symbolic links + */ + if (TestUtil.supportsLinks(tmpdir)) { + createSymbolicLink(thatFile, thisFile); + try { + assertTrue(isSameFile(thisFile, thatFile)); + assertTrue(isSameFile(thatFile, thisFile)); + } finally { + TestUtil.deleteUnchecked(thatFile); + } + } + } finally { + delete(thisFile); } + + // nulls try { - Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class), - -1, new SimpleFileVisitor(){}); - throw new RuntimeException("IllegalArgumentExpected expected"); - } catch (IllegalArgumentException e) { - } + isSameFile(thisFile, null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + try { + isSameFile(null, thatFile); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException ignore) { } + } + + /** + * Exercise isRegularFile, isDirectory, isSymbolicLink + */ + static void testFileTypeMethods(Path tmpdir) throws IOException { + assertTrue(!isRegularFile(tmpdir)); + assertTrue(!isRegularFile(tmpdir, NOFOLLOW_LINKS)); + assertTrue(isDirectory(tmpdir)); + assertTrue(isDirectory(tmpdir, NOFOLLOW_LINKS)); + assertTrue(!isSymbolicLink(tmpdir)); + + Path file = createFile(tmpdir.resolve("foo")); try { - Set opts = new HashSet(1); - opts.add(null); - Files.walkFileTree(Paths.get("."), opts, Integer.MAX_VALUE, - new SimpleFileVisitor(){}); - npeExpected(); - } catch (NullPointerException e) { + assertTrue(isRegularFile(file)); + assertTrue(isRegularFile(file, NOFOLLOW_LINKS)); + assertTrue(!isDirectory(file)); + assertTrue(!isDirectory(file, NOFOLLOW_LINKS)); + assertTrue(!isSymbolicLink(file)); + + if (TestUtil.supportsLinks(tmpdir)) { + Path link = tmpdir.resolve("link"); + + createSymbolicLink(link, tmpdir); + try { + assertTrue(!isRegularFile(link)); + assertTrue(!isRegularFile(link, NOFOLLOW_LINKS)); + assertTrue(isDirectory(link)); + assertTrue(!isDirectory(link, NOFOLLOW_LINKS)); + assertTrue(isSymbolicLink(link)); + } finally { + delete(link); + } + + createSymbolicLink(link, file); + try { + assertTrue(isRegularFile(link)); + assertTrue(!isRegularFile(link, NOFOLLOW_LINKS)); + assertTrue(!isDirectory(link)); + assertTrue(!isDirectory(link, NOFOLLOW_LINKS)); + assertTrue(isSymbolicLink(link)); + } finally { + delete(link); + } + + createLink(link, file); + try { + assertTrue(isRegularFile(link)); + assertTrue(isRegularFile(link, NOFOLLOW_LINKS)); + assertTrue(!isDirectory(link)); + assertTrue(!isDirectory(link, NOFOLLOW_LINKS)); + assertTrue(!isSymbolicLink(link)); + } finally { + delete(link); + } + } + + } finally { + delete(file); } + } + + /** + * Exercise isReadbale, isWritable, isExecutable, exists, notExists + */ + static void testAccessMethods(Path tmpdir) throws IOException { + // should return false when file does not exist + Path doesNotExist = tmpdir.resolve("doesNotExist"); + assertTrue(!isReadable(doesNotExist)); + assertTrue(!isWritable(doesNotExist)); + assertTrue(!isExecutable(doesNotExist)); + assertTrue(!exists(doesNotExist)); + assertTrue(notExists(doesNotExist)); + + Path file = createFile(tmpdir.resolve("foo")); try { - Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class), - Integer.MAX_VALUE, null); - npeExpected(); - } catch (NullPointerException e) { + // files exist + assertTrue(isReadable(file)); + assertTrue(isWritable(file)); + assertTrue(exists(file)); + assertTrue(!notExists(file)); + assertTrue(isReadable(tmpdir)); + assertTrue(isWritable(tmpdir)); + assertTrue(exists(tmpdir)); + assertTrue(!notExists(tmpdir)); + + + // sym link exists + if (TestUtil.supportsLinks(tmpdir)) { + Path link = tmpdir.resolve("link"); + + createSymbolicLink(link, file); + try { + assertTrue(isReadable(link)); + assertTrue(isWritable(link)); + assertTrue(exists(link)); + assertTrue(!notExists(link)); + } finally { + delete(link); + } + + createSymbolicLink(link, doesNotExist); + try { + assertTrue(!isReadable(link)); + assertTrue(!isWritable(link)); + assertTrue(!exists(link)); + assertTrue(exists(link, NOFOLLOW_LINKS)); + assertTrue(notExists(link)); + assertTrue(!notExists(link, NOFOLLOW_LINKS)); + } finally { + delete(link); + } + } + + /** + * Test: Edit ACL to deny WRITE and EXECUTE + */ + if (getFileStore(file).supportsFileAttributeView("acl")) { + AclFileAttributeView view = + getFileAttributeView(file, AclFileAttributeView.class); + UserPrincipal owner = view.getOwner(); + List acl = view.getAcl(); + + // Insert entry to deny WRITE and EXECUTE + AclEntry entry = AclEntry.newBuilder() + .setType(AclEntryType.DENY) + .setPrincipal(owner) + .setPermissions(AclEntryPermission.WRITE_DATA, + AclEntryPermission.EXECUTE) + .build(); + acl.add(0, entry); + view.setAcl(acl); + try { + assertTrue(!isWritable(file)); + assertTrue(!isExecutable(file)); + } finally { + // Restore ACL + acl.remove(0); + view.setAcl(acl); + } + } + + /** + * Test: Windows DOS read-only attribute + */ + if (System.getProperty("os.name").startsWith("Windows")) { + setAttribute(file, "dos:readonly", true); + try { + assertTrue(!isWritable(file)); + } finally { + setAttribute(file, "dos:readonly", false); + } + + // Read-only attribute does not make direcory read-only + DosFileAttributeView view = + getFileAttributeView(tmpdir, DosFileAttributeView.class); + boolean save = view.readAttributes().isReadOnly(); + view.setReadOnly(true); + try { + assertTrue(isWritable(file)); + } finally { + view.setReadOnly(save); + } + } + } finally { + delete(file); } + } - SimpleFileVisitor visitor = new SimpleFileVisitor() { }; - boolean ranTheGauntlet = false; - BasicFileAttributes attrs = Attributes.readBasicFileAttributes(Paths.get(".")); - - try { visitor.preVisitDirectory(null, attrs); - } catch (NullPointerException x0) { - try { visitor.preVisitDirectory(dir, null); - } catch (NullPointerException x1) { - try { visitor.visitFile(null, attrs); - } catch (NullPointerException x2) { - try { visitor.visitFile(dir, null); - } catch (NullPointerException x3) { - try { visitor.visitFileFailed(null, new IOException()); - } catch (NullPointerException x4) { - try { visitor.visitFileFailed(dir, null); - } catch (NullPointerException x5) { - try { visitor.postVisitDirectory(null, new IOException()); - } catch (NullPointerException x6) { - // if we get here then all visit* methods threw NPE as expected - ranTheGauntlet = true; - }}}}}}} - if (!ranTheGauntlet) - throw new RuntimeException("A visit method did not throw NPE"); + static void assertTrue(boolean okay) { + if (!okay) + throw new RuntimeException("Assertion Failed"); } } diff --git a/test/java/nio/file/Path/PassThroughFileSystem.java b/test/java/nio/file/Files/PassThroughFileSystem.java similarity index 74% rename from test/java/nio/file/Path/PassThroughFileSystem.java rename to test/java/nio/file/Files/PassThroughFileSystem.java index 4e77d12aba3741e10e803e3b46968ee02d42a7f7..31345a8bf36d124d0574b7ca27a6ec74d94709e0 100644 --- a/test/java/nio/file/Path/PassThroughFileSystem.java +++ b/test/java/nio/file/Files/PassThroughFileSystem.java @@ -54,6 +54,14 @@ class PassThroughFileSystem extends FileSystem { return provider.newFileSystem(uri, env); } + static Path unwrap(Path wrapper) { + if (wrapper == null) + throw new NullPointerException(); + if (!(wrapper instanceof PassThroughPath)) + throw new ProviderMismatchException(); + return ((PassThroughPath)wrapper).delegate; + } + @Override public FileSystemProvider provider() { return provider; @@ -117,8 +125,8 @@ class PassThroughFileSystem extends FileSystem { } @Override - public Path getPath(String path) { - return new PassThroughPath(this, delegate.getPath(path)); + public Path getPath(String first, String... more) { + return new PassThroughPath(this, delegate.getPath(first, more)); } @Override @@ -127,7 +135,7 @@ class PassThroughFileSystem extends FileSystem { return new PathMatcher() { @Override public boolean matches(Path path) { - return matcher.matches(PassThroughPath.unwrap(path)); + return matcher.matches(unwrap(path)); } }; } @@ -199,310 +207,293 @@ class PassThroughFileSystem extends FileSystem { uri.getSchemeSpecificPart()); return new PassThroughPath(delegate, delegate.provider().getPath(uri)); } - } - - static class PassThroughPath extends Path { - private final FileSystem fs; - private final Path delegate; - - PassThroughPath(FileSystem fs, Path delegate) { - this.fs = fs; - this.delegate = delegate; - } - - private Path wrap(Path path) { - return (path != null) ? new PassThroughPath(fs, path) : null; - } - - static Path unwrap(Path wrapper) { - if (!(wrapper instanceof PassThroughPath)) - throw new ProviderMismatchException(); - return ((PassThroughPath)wrapper).delegate; - } - - @Override - public FileSystem getFileSystem() { - return fs; - } @Override - public boolean isAbsolute() { - return delegate.isAbsolute(); - } - - @Override - public Path getRoot() { - return wrap(delegate.getRoot()); + public void setAttribute(Path file, String attribute, Object value, LinkOption... options) + throws IOException + { + Files.setAttribute(unwrap(file), attribute, value, options); } - @Override - public Path getName() { - return wrap(delegate.getName()); + public Map readAttributes(Path file, String attributes, LinkOption... options) + throws IOException + { + return Files.readAttributes(unwrap(file), attributes, options); } @Override - public Path getParent() { - return wrap(delegate.getParent()); + public V getFileAttributeView(Path file, + Class type, + LinkOption... options) + { + return Files.getFileAttributeView(unwrap(file), type, options); } @Override - public int getNameCount() { - return delegate.getNameCount(); + public A readAttributes(Path file, + Class type, + LinkOption... options) + throws IOException + { + return Files.readAttributes(unwrap(file), type, options); } @Override - public Path getName(int index) { - return wrap(delegate.getName(index)); + public void delete(Path file) throws IOException { + Files.delete(unwrap(file)); } @Override - public Path subpath(int beginIndex, int endIndex) { - return wrap(delegate.subpath(beginIndex, endIndex)); + public void createSymbolicLink(Path link, Path target, FileAttribute... attrs) + throws IOException + { + Files.createSymbolicLink(unwrap(link), unwrap(target), attrs); } @Override - public boolean startsWith(Path other) { - return delegate.startsWith(unwrap(other)); + public void createLink(Path link, Path existing) throws IOException { + Files.createLink(unwrap(link), unwrap(existing)); } @Override - public boolean endsWith(Path other) { - return delegate.endsWith(unwrap(other)); + public Path readSymbolicLink(Path link) throws IOException { + Path target = Files.readSymbolicLink(unwrap(link)); + return new PassThroughPath(delegate, target); } - @Override - public Path normalize() { - return wrap(delegate.normalize()); - } @Override - public Path resolve(Path other) { - return wrap(delegate.resolve(unwrap(other))); + public void copy(Path source, Path target, CopyOption... options) throws IOException { + Files.copy(unwrap(source), unwrap(target), options); } @Override - public Path resolve(String other) { - return wrap(delegate.resolve(other)); + public void move(Path source, Path target, CopyOption... options) throws IOException { + Files.move(unwrap(source), unwrap(target), options); } - @Override - public Path relativize(Path other) { - return wrap(delegate.relativize(unwrap(other))); + private DirectoryStream wrap(final DirectoryStream stream) { + return new DirectoryStream() { + @Override + public Iterator iterator() { + final Iterator itr = stream.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return itr.hasNext(); + } + @Override + public Path next() { + return new PassThroughPath(delegate, itr.next()); + } + @Override + public void remove() { + itr.remove(); + } + }; + } + @Override + public void close() throws IOException { + stream.close(); + } + }; } @Override - public void setAttribute(String attribute, Object value, LinkOption... options) + public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) throws IOException { - delegate.setAttribute(attribute, value, options); + return wrap(Files.newDirectoryStream(dir, filter)); } @Override - public Object getAttribute(String attribute, LinkOption... options) + public void createDirectory(Path dir, FileAttribute... attrs) throws IOException { - // assume that unwrapped objects aren't exposed - return delegate.getAttribute(attribute, options); + Files.createDirectory(unwrap(dir), attrs); } @Override - public Map readAttributes(String attributes, LinkOption... options) + public SeekableByteChannel newByteChannel(Path file, + Set options, + FileAttribute... attrs) throws IOException { - // assume that unwrapped objects aren't exposed - return delegate.readAttributes(attributes, options); + return Files.newByteChannel(unwrap(file), options, attrs); } + @Override - public V getFileAttributeView(Class type, - LinkOption... options) - { - return delegate.getFileAttributeView(type, options); + public boolean isHidden(Path file) throws IOException { + return Files.isHidden(unwrap(file)); } @Override - public void delete() throws IOException { - delegate.delete(); + public FileStore getFileStore(Path file) throws IOException { + return Files.getFileStore(unwrap(file)); } @Override - public void deleteIfExists() throws IOException { - delegate.deleteIfExists(); + public boolean isSameFile(Path file, Path other) throws IOException { + return Files.isSameFile(unwrap(file), unwrap(other)); } @Override - public Path createSymbolicLink(Path target, FileAttribute... attrs) + public void checkAccess(Path file, AccessMode... modes) throws IOException { - delegate.createSymbolicLink(unwrap(target), attrs); - return this; + // hack + if (modes.length == 0) { + if (Files.exists(unwrap(file))) + return; + else + throw new NoSuchFileException(file.toString()); + } + throw new RuntimeException("not implemented yet"); + } + } + + static class PassThroughPath implements Path { + private final FileSystem fs; + private final Path delegate; + + PassThroughPath(FileSystem fs, Path delegate) { + this.fs = fs; + this.delegate = delegate; + } + + private Path wrap(Path path) { + return (path != null) ? new PassThroughPath(fs, path) : null; } @Override - public Path createLink(Path existing) throws IOException { - delegate.createLink(unwrap(existing)); - return this; + public FileSystem getFileSystem() { + return fs; } @Override - public Path readSymbolicLink() throws IOException { - return wrap(delegate.readSymbolicLink()); + public boolean isAbsolute() { + return delegate.isAbsolute(); } @Override - public URI toUri() { - String ssp = delegate.toUri().getSchemeSpecificPart(); - return URI.create(fs.provider().getScheme() + ":" + ssp); + public Path getRoot() { + return wrap(delegate.getRoot()); } @Override - public Path toAbsolutePath() { - return wrap(delegate.toAbsolutePath()); + public Path getParent() { + return wrap(delegate.getParent()); } @Override - public Path toRealPath(boolean resolveLinks) throws IOException { - return wrap(delegate.toRealPath(resolveLinks)); + public int getNameCount() { + return delegate.getNameCount(); } @Override - public Path copyTo(Path target, CopyOption... options) throws IOException { - return wrap(delegate.copyTo(unwrap(target), options)); + public Path getFileName() { + return wrap(delegate.getFileName()); } @Override - public Path moveTo(Path target, CopyOption... options) throws IOException { - return wrap(delegate.copyTo(unwrap(target), options)); + public Path getName(int index) { + return wrap(delegate.getName(index)); } - private DirectoryStream wrap(final DirectoryStream stream) { - return new DirectoryStream() { - @Override - public Iterator iterator() { - final Iterator itr = stream.iterator(); - return new Iterator() { - @Override - public boolean hasNext() { - return itr.hasNext(); - } - @Override - public Path next() { - return wrap(itr.next()); - } - @Override - public void remove() { - itr.remove(); - } - }; - } - @Override - public void close() throws IOException { - stream.close(); - } - }; + @Override + public Path subpath(int beginIndex, int endIndex) { + return wrap(delegate.subpath(beginIndex, endIndex)); } @Override - public DirectoryStream newDirectoryStream() throws IOException { - return wrap(delegate.newDirectoryStream()); + public boolean startsWith(Path other) { + return delegate.startsWith(unwrap(other)); } @Override - public DirectoryStream newDirectoryStream(String glob) - throws IOException - { - return wrap(delegate.newDirectoryStream(glob)); + public boolean startsWith(String other) { + return delegate.startsWith(other); } @Override - public DirectoryStream newDirectoryStream(DirectoryStream.Filter filter) - throws IOException - { - return wrap(delegate.newDirectoryStream(filter)); + public boolean endsWith(Path other) { + return delegate.endsWith(unwrap(other)); } @Override - public Path createFile(FileAttribute... attrs) throws IOException { - delegate.createFile(attrs); - return this; + public boolean endsWith(String other) { + return delegate.endsWith(other); } @Override - public Path createDirectory(FileAttribute... attrs) - throws IOException - { - delegate.createDirectory(attrs); - return this; + public Path normalize() { + return wrap(delegate.normalize()); } @Override - public SeekableByteChannel newByteChannel(Set options, - FileAttribute... attrs) - throws IOException - { - return delegate.newByteChannel(options, attrs); + public Path resolve(Path other) { + return wrap(delegate.resolve(unwrap(other))); } @Override - public SeekableByteChannel newByteChannel(OpenOption... options) - throws IOException - { - return delegate.newByteChannel(options); + public Path resolve(String other) { + return wrap(delegate.resolve(other)); } @Override - public InputStream newInputStream(OpenOption... options) throws IOException { - return delegate.newInputStream(); + public Path resolveSibling(Path other) { + return wrap(delegate.resolveSibling(unwrap(other))); } @Override - public OutputStream newOutputStream(OpenOption... options) - throws IOException - { - return delegate.newOutputStream(options); + public Path resolveSibling(String other) { + return wrap(delegate.resolveSibling(other)); } @Override - public boolean isHidden() throws IOException { - return delegate.isHidden(); + public Path relativize(Path other) { + return wrap(delegate.relativize(unwrap(other))); } @Override - public void checkAccess(AccessMode... modes) throws IOException { - delegate.checkAccess(modes); + public boolean equals(Object other) { + if (!(other instanceof PassThroughPath)) + return false; + return delegate.equals(unwrap((PassThroughPath)other)); } @Override - public boolean exists() { - return delegate.exists(); + public int hashCode() { + return delegate.hashCode(); } @Override - public boolean notExists() { - return delegate.notExists(); + public String toString() { + return delegate.toString(); } @Override - public FileStore getFileStore() throws IOException { - return delegate.getFileStore(); + public URI toUri() { + String ssp = delegate.toUri().getSchemeSpecificPart(); + return URI.create(fs.provider().getScheme() + ":" + ssp); } @Override - public WatchKey register(WatchService watcher, - WatchEvent.Kind[] events, - WatchEvent.Modifier... modifiers) - { - throw new UnsupportedOperationException(); + public Path toAbsolutePath() { + return wrap(delegate.toAbsolutePath()); } @Override - public WatchKey register(WatchService watcher, - WatchEvent.Kind... events) - { - throw new UnsupportedOperationException(); + public Path toRealPath(boolean resolveLinks) throws IOException { + return wrap(delegate.toRealPath(resolveLinks)); } + @Override + public File toFile() { + return delegate.toFile(); + } @Override public Iterator iterator() { @@ -529,26 +520,18 @@ class PassThroughFileSystem extends FileSystem { } @Override - public boolean isSameFile(Path other) throws IOException { - return delegate.isSameFile(unwrap(other)); - } - - - @Override - public boolean equals(Object other) { - if (!(other instanceof PassThroughPath)) - return false; - return delegate.equals(unwrap((PassThroughPath)other)); - } - - @Override - public int hashCode() { - return delegate.hashCode(); + public WatchKey register(WatchService watcher, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) + { + throw new UnsupportedOperationException(); } @Override - public String toString() { - return delegate.toString(); + public WatchKey register(WatchService watcher, + WatchEvent.Kind... events) + { + throw new UnsupportedOperationException(); } } } diff --git a/test/java/nio/file/Path/SBC.java b/test/java/nio/file/Files/SBC.java similarity index 74% rename from test/java/nio/file/Path/SBC.java rename to test/java/nio/file/Files/SBC.java index 8a5501b3549913f5c502eb2c71004f6e236020f4..6dcf1a92fc01c24963f51b4b20ad5f22ed1cfb88 100644 --- a/test/java/nio/file/Path/SBC.java +++ b/test/java/nio/file/Files/SBC.java @@ -23,7 +23,7 @@ /* @test * @bug 4313887 - * @summary Unit test for java.nio.file.Path.newByteChannel + * @summary Unit test for java.nio.file.Files.newByteChannel * @library .. */ @@ -75,24 +75,24 @@ public class SBC { // CREATE try { // create file (no existing file) - file.newByteChannel(CREATE, WRITE).close(); - if (file.notExists()) + Files.newByteChannel(file, CREATE, WRITE).close(); + if (Files.notExists(file)) throw new RuntimeException("File not created"); // create file (existing file) - file.newByteChannel(CREATE, WRITE).close(); + Files.newByteChannel(file, CREATE, WRITE).close(); // create file where existing file is a sym link if (supportsLinks) { - Path link = dir.resolve("link").createSymbolicLink(file); + Path link = Files.createSymbolicLink(dir.resolve("link"), file); try { // file already exists - link.newByteChannel(CREATE, WRITE).close(); + Files.newByteChannel(link, CREATE, WRITE).close(); // file does not exist - file.delete(); - link.newByteChannel(CREATE, WRITE).close(); - if (file.notExists()) + Files.delete(file); + Files.newByteChannel(link, CREATE, WRITE).close(); + if (Files.notExists(file)) throw new RuntimeException("File not created"); } finally { @@ -107,14 +107,14 @@ public class SBC { // CREATE_NEW try { // create file - file.newByteChannel(CREATE_NEW, WRITE).close(); - if (file.notExists()) + Files.newByteChannel(file, CREATE_NEW, WRITE).close(); + if (Files.notExists(file)) throw new RuntimeException("File not created"); // create should fail try { SeekableByteChannel sbc = - file.newByteChannel(CREATE_NEW, WRITE); + Files.newByteChannel(file, CREATE_NEW, WRITE); sbc.close(); throw new RuntimeException("FileAlreadyExistsException not thrown"); } catch (FileAlreadyExistsException x) { } @@ -123,12 +123,12 @@ public class SBC { if (supportsLinks) { Path link = dir.resolve("link"); Path target = dir.resolve("thisDoesNotExist"); - link.createSymbolicLink(target); + Files.createSymbolicLink(link, target); try { try { SeekableByteChannel sbc = - file.newByteChannel(CREATE_NEW, WRITE); + Files.newByteChannel(file, CREATE_NEW, WRITE); sbc.close(); throw new RuntimeException("FileAlreadyExistsException not thrown"); } catch (FileAlreadyExistsException x) { } @@ -145,17 +145,13 @@ public class SBC { // CREATE_NEW + SPARSE try { - SeekableByteChannel sbc = file - .newByteChannel(CREATE_NEW, WRITE, SPARSE); - try { + try (SeekableByteChannel sbc = Files.newByteChannel(file, CREATE_NEW, WRITE, SPARSE)) { final long hole = 2L * 1024L * 1024L * 1024L; sbc.position(hole); write(sbc, "hello"); long size = sbc.size(); if (size != (hole + 5)) throw new RuntimeException("Unexpected size"); - } finally { - sbc.close(); } } finally { TestUtil.deleteUnchecked(file); @@ -167,33 +163,23 @@ public class SBC { Path file = dir.resolve("foo"); try { // "hello there" should be written to file - SeekableByteChannel sbc = file - .newByteChannel(CREATE_NEW, WRITE, APPEND); - try { + try (SeekableByteChannel sbc = Files.newByteChannel(file, CREATE_NEW, WRITE, APPEND)) { write(sbc, "hello "); sbc.position(0L); write(sbc, "there"); - } finally { - sbc.close(); } // check file - Scanner s = new Scanner(file); - try { + try (Scanner s = new Scanner(file)) { String line = s.nextLine(); if (!line.equals("hello there")) throw new RuntimeException("Unexpected file contents"); - } finally { - s.close(); } // check that read is not allowed - sbc = file.newByteChannel(APPEND); - try { + try (SeekableByteChannel sbc = Files.newByteChannel(file, APPEND)) { sbc.read(ByteBuffer.allocate(100)); } catch (NonReadableChannelException x) { - } finally { - sbc.close(); } } finally { // clean-up @@ -205,40 +191,27 @@ public class SBC { static void truncateExistingTests(Path dir) throws Exception { Path file = dir.resolve("foo"); try { - SeekableByteChannel sbc = - file.newByteChannel(CREATE_NEW, WRITE); - try { + try (SeekableByteChannel sbc = Files.newByteChannel(file, CREATE_NEW, WRITE)) { write(sbc, "Have a nice day!"); - } finally { - sbc.close(); } // re-open with truncate option // write short message and check - sbc = file.newByteChannel(WRITE, TRUNCATE_EXISTING); - try { + try (SeekableByteChannel sbc = Files.newByteChannel(file, WRITE, TRUNCATE_EXISTING)) { write(sbc, "Hello there!"); - } finally { - sbc.close(); } - Scanner s = new Scanner(file); - try { + try (Scanner s = new Scanner(file)) { String line = s.nextLine(); if (!line.equals("Hello there!")) throw new RuntimeException("Unexpected file contents"); - } finally { - s.close(); } // re-open with create + truncate option // check file is of size 0L - sbc = file.newByteChannel(WRITE, CREATE, TRUNCATE_EXISTING); - try { + try (SeekableByteChannel sbc = Files.newByteChannel(file, WRITE, CREATE, TRUNCATE_EXISTING)) { long size = ((FileChannel)sbc).size(); if (size != 0L) throw new RuntimeException("File not truncated"); - } finally { - sbc.close(); } } finally { @@ -252,14 +225,15 @@ public class SBC { static void noFollowLinksTests(Path dir) throws Exception { if (!supportsLinks) return; - Path file = dir.resolve("foo").createFile(); + Path file = Files.createFile(dir.resolve("foo")); try { // ln -s foo link - Path link = dir.resolve("link").createSymbolicLink(file); + Path link = dir.resolve("link"); + Files.createSymbolicLink(link, file); // open with NOFOLLOW_LINKS option try { - link.newByteChannel(READ, LinkOption.NOFOLLOW_LINKS); + Files.newByteChannel(link, READ, LinkOption.NOFOLLOW_LINKS); throw new RuntimeException(); } catch (IOException x) { } finally { @@ -276,9 +250,7 @@ public class SBC { static void sizeTruncatePositionTests(Path dir) throws Exception { Path file = dir.resolve("foo"); try { - SeekableByteChannel sbc = file - .newByteChannel(CREATE_NEW, READ, WRITE); - try { + try (SeekableByteChannel sbc = Files.newByteChannel(file, CREATE_NEW, READ, WRITE)) { if (sbc.size() != 0L) throw new RuntimeException("Unexpected size"); @@ -300,8 +272,6 @@ public class SBC { throw new RuntimeException("Unexpected size"); if (sbc.position() != 2L) throw new RuntimeException("Unexpected position"); - } finally { - sbc.close(); } } finally { TestUtil.deleteUnchecked(file); @@ -311,76 +281,63 @@ public class SBC { // Windows specific options for the use by applications that really want // to use legacy DOS sharing options static void dosSharingOptionTests(Path dir) throws Exception { - Path file = dir.resolve("foo").createFile(); + Path file = Files.createFile(dir.resolve("foo")); try { - SeekableByteChannel ch; - // no sharing - ch = file.newByteChannel(READ, - NOSHARE_READ, NOSHARE_WRITE, NOSHARE_DELETE); - try { + try (SeekableByteChannel ch = Files.newByteChannel(file, READ, NOSHARE_READ, + NOSHARE_WRITE, NOSHARE_DELETE)) + { try { - file.newByteChannel(READ); + Files.newByteChannel(file, READ); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } try { - file.newByteChannel(WRITE); + Files.newByteChannel(file, WRITE); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } try { - file.delete(); + Files.delete(file); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } - } finally { - ch.close(); } // read allowed - ch = file.newByteChannel(READ, NOSHARE_WRITE, NOSHARE_DELETE); - try { - file.newByteChannel(READ).close(); + try (SeekableByteChannel ch = Files.newByteChannel(file, READ, NOSHARE_WRITE, NOSHARE_DELETE)) { + Files.newByteChannel(file, READ).close(); try { - file.newByteChannel(WRITE); + Files.newByteChannel(file, WRITE); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } try { - file.delete(); + Files.delete(file); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } - } finally { - ch.close(); } // write allowed - ch = file.newByteChannel(READ, NOSHARE_READ, NOSHARE_DELETE); - try { + try (SeekableByteChannel ch = Files.newByteChannel(file, READ, NOSHARE_READ, NOSHARE_DELETE)) { try { - file.newByteChannel(READ); + Files.newByteChannel(file, READ); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } - file.newByteChannel(WRITE).close(); + Files.newByteChannel(file, WRITE).close(); try { - file.delete(); + Files.delete(file); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } - } finally { - ch.close(); } // delete allowed - ch = file.newByteChannel(READ, NOSHARE_READ, NOSHARE_WRITE); - try { + try (SeekableByteChannel ch = Files.newByteChannel(file, READ, NOSHARE_READ, NOSHARE_WRITE)) { try { - file.newByteChannel(READ); + Files.newByteChannel(file, READ); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } try { - file.newByteChannel(WRITE); + Files.newByteChannel(file, WRITE); throw new RuntimeException("Sharing violation expected"); } catch (IOException ignore) { } - file.delete(); - } finally { - ch.close(); + Files.delete(file); } } finally { @@ -393,12 +350,12 @@ public class SBC { Path file = dir.resolve("bad"); try { - file.newByteChannel(READ, APPEND); + Files.newByteChannel(file, READ, APPEND); throw new RuntimeException("IllegalArgumentException expected"); } catch (IllegalArgumentException x) { } try { - file.newByteChannel(WRITE, APPEND, TRUNCATE_EXISTING); + Files.newByteChannel(file, WRITE, APPEND, TRUNCATE_EXISTING); throw new RuntimeException("IllegalArgumentException expected"); } catch (IllegalArgumentException x) { } } @@ -409,11 +366,11 @@ public class SBC { OpenOption badOption = new OpenOption() { }; try { - file.newByteChannel(badOption); + Files.newByteChannel(file, badOption); throw new RuntimeException("UnsupportedOperationException expected"); } catch (UnsupportedOperationException e) { } try { - file.newByteChannel(READ, WRITE, badOption); + Files.newByteChannel(file, READ, WRITE, badOption); throw new RuntimeException("UnsupportedOperationException expected"); } catch (UnsupportedOperationException e) { } } @@ -423,39 +380,45 @@ public class SBC { Path file = dir.resolve("foo"); try { - file.newByteChannel((OpenOption[])null); + OpenOption[] opts = { READ, null }; + Files.newByteChannel((Path)null, opts); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + Files.newByteChannel(file, (OpenOption[])null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { OpenOption[] opts = { READ, null }; - file.newByteChannel(opts); + Files.newByteChannel(file, opts); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { - file.newByteChannel((Set)null); + Files.newByteChannel(file, (Set)null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { - Set opts = new HashSet(); + Set opts = new HashSet<>(); opts.add(READ); opts.add(null); - file.newByteChannel(opts); + Files.newByteChannel(file, opts); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { EnumSet opts = EnumSet.of(READ); - file.newByteChannel(opts, (FileAttribute[])null); + Files.newByteChannel(file, opts, (FileAttribute[])null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } try { EnumSet opts = EnumSet.of(READ); FileAttribute[] attrs = { null }; - file.newByteChannel(opts, attrs); + Files.newByteChannel(file, opts, attrs); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException x) { } } diff --git a/test/java/nio/file/Files/TemporaryFiles.java b/test/java/nio/file/Files/TemporaryFiles.java new file mode 100644 index 0000000000000000000000000000000000000000..3c1087e4e530ad2956629f4ffe9fff1e6c932643 --- /dev/null +++ b/test/java/nio/file/Files/TemporaryFiles.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2008, 2009, 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 4313887 6838333 7006126 + * @summary Unit test for Files.createTempXXX + * @library .. + */ + +import java.nio.file.*; +import static java.nio.file.StandardOpenOption.*; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.Set; + +public class TemporaryFiles { + + static void checkInDirectory(Path file, Path dir) { + if (dir == null) + dir = Paths.get(System.getProperty("java.io.tmpdir")); + if (!file.getParent().equals(dir)) + throw new RuntimeException("Not in expected directory"); + } + + static void testTempFile(String prefix, String suffix, Path dir) + throws IOException + { + Path file = (dir == null) ? + Files.createTempFile(prefix, suffix) : + Files.createTempFile(dir, prefix, suffix); + try { + // check file name + String name = file.getFileName().toString(); + if (prefix != null && !name.startsWith(prefix)) + throw new RuntimeException("Should start with " + prefix); + if (suffix == null && !name.endsWith(".tmp")) + throw new RuntimeException("Should end with .tmp"); + if (suffix != null && !name.endsWith(suffix)) + throw new RuntimeException("Should end with " + suffix); + + // check file is in expected directory + checkInDirectory(file, dir); + + // check that file can be opened for reading and writing + Files.newByteChannel(file, READ).close(); + Files.newByteChannel(file, WRITE).close(); + Files.newByteChannel(file, READ,WRITE).close(); + + // check file permissions are 0600 or more secure + if (Files.getFileStore(file).supportsFileAttributeView("posix")) { + Set perms = Files.getPosixFilePermissions(file); + perms.remove(PosixFilePermission.OWNER_READ); + perms.remove(PosixFilePermission.OWNER_WRITE); + if (!perms.isEmpty()) + throw new RuntimeException("Temporary file is not secure"); + } + } finally { + Files.delete(file); + } + } + + static void testTempFile(String prefix, String suffix) + throws IOException + { + testTempFile(prefix, suffix, null); + } + + static void testTempDirectory(String prefix, Path dir) throws IOException { + Path subdir = (dir == null) ? + Files.createTempDirectory(prefix) : + Files.createTempDirectory(dir, prefix); + try { + // check file name + String name = subdir.getFileName().toString(); + if (prefix != null && !name.startsWith(prefix)) + throw new RuntimeException("Should start with " + prefix); + + // check directory is in expected directory + checkInDirectory(subdir, dir); + + // check directory is empty + DirectoryStream stream = Files.newDirectoryStream(subdir); + try { + if (stream.iterator().hasNext()) + throw new RuntimeException("Tempory directory not empty"); + } finally { + stream.close(); + } + + // check that we can create file in directory + Path file = Files.createFile(subdir.resolve("foo")); + try { + Files.newByteChannel(file, READ,WRITE).close(); + } finally { + Files.delete(file); + } + + // check file permissions are 0700 or more secure + if (Files.getFileStore(subdir).supportsFileAttributeView("posix")) { + Set perms = Files.getPosixFilePermissions(subdir); + perms.remove(PosixFilePermission.OWNER_READ); + perms.remove(PosixFilePermission.OWNER_WRITE); + perms.remove(PosixFilePermission.OWNER_EXECUTE); + if (!perms.isEmpty()) + throw new RuntimeException("Temporary directory is not secure"); + } + } finally { + Files.delete(subdir); + } + } + + static void testTempDirectory(String prefix) throws IOException { + testTempDirectory(prefix, null); + } + + static void testInvalidFileTemp(String prefix, String suffix) throws IOException { + try { + Path file = Files.createTempFile(prefix, suffix); + Files.delete(file); + throw new RuntimeException("IllegalArgumentException expected"); + } catch (IllegalArgumentException expected) { } + } + + public static void main(String[] args) throws IOException { + // temporary-file directory + testTempFile("blah", ".dat"); + testTempFile("blah", null); + testTempFile(null, ".dat"); + testTempFile(null, null); + testTempDirectory("blah"); + testTempDirectory(null); + + // a given directory + Path dir = Files.createTempDirectory("tmpdir"); + try { + testTempFile("blah", ".dat", dir); + testTempFile("blah", null, dir); + testTempFile(null, ".dat", dir); + testTempFile(null, null, dir); + testTempDirectory("blah", dir); + testTempDirectory(null, dir); + } finally { + Files.delete(dir); + } + + // invalid prefix and suffix + testInvalidFileTemp("../blah", null); + testInvalidFileTemp("dir/blah", null); + testInvalidFileTemp("blah", ".dat/foo"); + } +} diff --git a/test/java/nio/file/Path/delete_on_close.sh b/test/java/nio/file/Files/delete_on_close.sh similarity index 100% rename from test/java/nio/file/Path/delete_on_close.sh rename to test/java/nio/file/Files/delete_on_close.sh diff --git a/test/java/nio/file/Files/ContentType.java b/test/java/nio/file/Files/probeContentType/Basic.java similarity index 85% rename from test/java/nio/file/Files/ContentType.java rename to test/java/nio/file/Files/probeContentType/Basic.java index 33a0aeb6e141cd8554eb3db79205011a42f365ff..ce692121d1c11154693fbd85aac7c43c034f9f84 100644 --- a/test/java/nio/file/Files/ContentType.java +++ b/test/java/nio/file/Files/probeContentType/Basic.java @@ -24,9 +24,9 @@ /* @test * @bug 4313887 * @summary Unit test for probeContentType method - * @library .. - * @build ContentType SimpleFileTypeDetector - * @run main/othervm ContentType + * @library ../.. + * @build Basic SimpleFileTypeDetector + * @run main/othervm Basic */ import java.nio.file.*; @@ -36,22 +36,19 @@ import java.io.*; * Uses Files.probeContentType to probe html file and custom file type. */ -public class ContentType { +public class Basic { static Path createHtmlFile() throws IOException { - Path file = File.createTempFile("foo", ".html").toPath(); - OutputStream out = file.newOutputStream(); - try { + Path file = Files.createTempFile("foo", ".html"); + try (OutputStream out = Files.newOutputStream(file)) { out.write("foo".getBytes()); - } finally { - out.close(); } return file; } static Path createGrapeFile() throws IOException { - return File.createTempFile("red", ".grape").toPath(); + return Files.createTempFile("red", ".grape"); } public static void main(String[] args) throws IOException { @@ -67,7 +64,7 @@ public class ContentType { throw new RuntimeException("Unexpected type: " + type); } } finally { - file.delete(); + Files.delete(file); } // exercise custom file type detector @@ -79,7 +76,7 @@ public class ContentType { if (!type.equals("grape/unknown")) throw new RuntimeException("Unexpected type: " + type); } finally { - file.delete(); + Files.delete(file); } } diff --git a/test/java/nio/file/Files/ForceLoad.java b/test/java/nio/file/Files/probeContentType/ForceLoad.java similarity index 100% rename from test/java/nio/file/Files/ForceLoad.java rename to test/java/nio/file/Files/probeContentType/ForceLoad.java diff --git a/test/java/nio/file/Files/META-INF/services/java.nio.file.spi.FileTypeDetector b/test/java/nio/file/Files/probeContentType/META-INF/services/java.nio.file.spi.FileTypeDetector similarity index 100% rename from test/java/nio/file/Files/META-INF/services/java.nio.file.spi.FileTypeDetector rename to test/java/nio/file/Files/probeContentType/META-INF/services/java.nio.file.spi.FileTypeDetector diff --git a/test/java/nio/file/Files/SimpleFileTypeDetector.java b/test/java/nio/file/Files/probeContentType/SimpleFileTypeDetector.java similarity index 81% rename from test/java/nio/file/Files/SimpleFileTypeDetector.java rename to test/java/nio/file/Files/probeContentType/SimpleFileTypeDetector.java index 590d9a474c1a8a67fb938b07762b8648455cc736..a6b0e76ecd8f2c80895e013c5bda76018ad51298 100644 --- a/test/java/nio/file/Files/SimpleFileTypeDetector.java +++ b/test/java/nio/file/Files/probeContentType/SimpleFileTypeDetector.java @@ -30,18 +30,9 @@ public class SimpleFileTypeDetector extends FileTypeDetector { public SimpleFileTypeDetector() { } - public String probeContentType(FileRef file) throws IOException { - + public String probeContentType(Path file) throws IOException { System.out.println("probe " + file + "..."); - - if (file instanceof Path) { - String name = ((Path)file).toString(); - if (name.endsWith(".grape")) { - return "grape/unknown"; - } - } - - // unknown - return null; + String name = file.toString(); + return name.endsWith(".grape") ? "grape/unknown" : null; } } diff --git a/test/java/nio/file/Files/CreateFileTree.java b/test/java/nio/file/Files/walkFileTree/CreateFileTree.java similarity index 81% rename from test/java/nio/file/Files/CreateFileTree.java rename to test/java/nio/file/Files/walkFileTree/CreateFileTree.java index 1ff7aa6e91b11786637530477ea15348f0b8c082..c00f058152da6739b14ec9d84da95bf78ec97254 100644 --- a/test/java/nio/file/Files/CreateFileTree.java +++ b/test/java/nio/file/Files/walkFileTree/CreateFileTree.java @@ -34,21 +34,8 @@ public class CreateFileTree { static final Random rand = new Random(); - public static Path createTemporaryDirectory() throws IOException { - Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); - Path dir; - do { - dir = tmpdir.resolve("name" + rand.nextInt()); - } while (dir.exists()); - dir.createDirectory(); - return dir; - } - public static void main(String[] args) throws IOException { - Path top = createTemporaryDirectory(); - if (!top.isAbsolute()) - top = top.toAbsolutePath(); - + Path top = Files.createTempDirectory("tree"); List dirs = new ArrayList(); // create tree @@ -61,7 +48,7 @@ public class CreateFileTree { int r = Math.min((total-n), (1+rand.nextInt(3))); for (int i=0; i(){}); + npeExpected(); + } catch (NullPointerException e) { + } + try { + Files.walkFileTree(Paths.get("."), null, Integer.MAX_VALUE, + new SimpleFileVisitor(){}); + npeExpected(); + } catch (NullPointerException e) { + } + try { + Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class), + -1, new SimpleFileVisitor(){}); + throw new RuntimeException("IllegalArgumentExpected expected"); + } catch (IllegalArgumentException e) { + } + try { + Set opts = new HashSet<>(1); + opts.add(null); + Files.walkFileTree(Paths.get("."), opts, Integer.MAX_VALUE, + new SimpleFileVisitor(){}); + npeExpected(); + } catch (NullPointerException e) { + } + try { + Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class), + Integer.MAX_VALUE, null); + npeExpected(); + } catch (NullPointerException e) { + } + + SimpleFileVisitor visitor = new SimpleFileVisitor() { }; + boolean ranTheGauntlet = false; + Path dir = Paths.get("."); + BasicFileAttributes attrs = Files.readAttributes(dir, BasicFileAttributes.class); + + try { visitor.preVisitDirectory(null, attrs); + } catch (NullPointerException x0) { + try { visitor.preVisitDirectory(dir, null); + } catch (NullPointerException x1) { + try { visitor.visitFile(null, attrs); + } catch (NullPointerException x2) { + try { visitor.visitFile(dir, null); + } catch (NullPointerException x3) { + try { visitor.visitFileFailed(null, new IOException()); + } catch (NullPointerException x4) { + try { visitor.visitFileFailed(dir, null); + } catch (NullPointerException x5) { + try { visitor.postVisitDirectory(null, new IOException()); + } catch (NullPointerException x6) { + // if we get here then all visit* methods threw NPE as expected + ranTheGauntlet = true; + }}}}}}} + if (!ranTheGauntlet) + throw new RuntimeException("A visit method did not throw NPE"); + } +} diff --git a/test/java/nio/file/Files/PrintFileTree.java b/test/java/nio/file/Files/walkFileTree/PrintFileTree.java similarity index 89% rename from test/java/nio/file/Files/PrintFileTree.java rename to test/java/nio/file/Files/walkFileTree/PrintFileTree.java index 41ddb95a317fde6c1f14a7e0d9afb530d2051f3e..83d554dc6898b4fedb0625906937f35936a87ab4 100644 --- a/test/java/nio/file/Files/PrintFileTree.java +++ b/test/java/nio/file/Files/walkFileTree/PrintFileTree.java @@ -55,20 +55,20 @@ public class PrintFileTree { options.add(FileVisitOption.FOLLOW_LINKS); final boolean reportCycles = printCycles; - Files.walkFileTree(dir, options, Integer.MAX_VALUE, new FileVisitor() { + Files.walkFileTree(dir, options, Integer.MAX_VALUE, new FileVisitor() { @Override - public FileVisitResult preVisitDirectory(FileRef dir, BasicFileAttributes attrs) { + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { System.out.println(dir); return FileVisitResult.CONTINUE; } @Override - public FileVisitResult visitFile(FileRef file, BasicFileAttributes attrs) { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { if (!attrs.isDirectory() || reportCycles) System.out.println(file); return FileVisitResult.CONTINUE; } @Override - public FileVisitResult postVisitDirectory(FileRef dir, IOException exc) + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if (exc != null) @@ -76,7 +76,7 @@ public class PrintFileTree { return FileVisitResult.CONTINUE; } @Override - public FileVisitResult visitFileFailed(FileRef file, IOException exc) + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (reportCycles && (exc instanceof FileSystemLoopException)) { diff --git a/test/java/nio/file/Files/SkipSiblings.java b/test/java/nio/file/Files/walkFileTree/SkipSiblings.java similarity index 100% rename from test/java/nio/file/Files/SkipSiblings.java rename to test/java/nio/file/Files/walkFileTree/SkipSiblings.java diff --git a/test/java/nio/file/Files/TerminateWalk.java b/test/java/nio/file/Files/walkFileTree/TerminateWalk.java similarity index 100% rename from test/java/nio/file/Files/TerminateWalk.java rename to test/java/nio/file/Files/walkFileTree/TerminateWalk.java diff --git a/test/java/nio/file/Files/WalkWithSecurity.java b/test/java/nio/file/Files/walkFileTree/WalkWithSecurity.java similarity index 94% rename from test/java/nio/file/Files/WalkWithSecurity.java rename to test/java/nio/file/Files/walkFileTree/WalkWithSecurity.java index 2a1f67f492e4154490f8d49ea2ba98b700c05244..91e61c476be5cc7dc85755f9eb104e37258a604c 100644 --- a/test/java/nio/file/Files/WalkWithSecurity.java +++ b/test/java/nio/file/Files/walkFileTree/WalkWithSecurity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -47,14 +47,11 @@ public class WalkWithSecurity { Path dir = Paths.get(testSrc); // Sanity check the environment - if (Paths.get(here).isSameFile(dir)) + if (Files.isSameFile(Paths.get(here), dir)) throw new RuntimeException("Working directory cannot be " + dir); - DirectoryStream stream = dir.newDirectoryStream(); - try { + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { if (!stream.iterator().hasNext()) throw new RuntimeException(testSrc + " is empty"); - } finally { - stream.close(); } // Install security manager with the given policy file diff --git a/test/java/nio/file/Files/denyAll.policy b/test/java/nio/file/Files/walkFileTree/denyAll.policy similarity index 100% rename from test/java/nio/file/Files/denyAll.policy rename to test/java/nio/file/Files/walkFileTree/denyAll.policy diff --git a/test/java/nio/file/Files/grantAll.policy b/test/java/nio/file/Files/walkFileTree/grantAll.policy similarity index 100% rename from test/java/nio/file/Files/grantAll.policy rename to test/java/nio/file/Files/walkFileTree/grantAll.policy diff --git a/test/java/nio/file/Files/grantTopOnly.policy b/test/java/nio/file/Files/walkFileTree/grantTopOnly.policy similarity index 100% rename from test/java/nio/file/Files/grantTopOnly.policy rename to test/java/nio/file/Files/walkFileTree/grantTopOnly.policy diff --git a/test/java/nio/file/Files/walk_file_tree.sh b/test/java/nio/file/Files/walkFileTree/walk_file_tree.sh similarity index 100% rename from test/java/nio/file/Files/walk_file_tree.sh rename to test/java/nio/file/Files/walkFileTree/walk_file_tree.sh diff --git a/test/java/nio/file/Path/Misc.java b/test/java/nio/file/Path/Misc.java index dba06f1dd065a2b4931ea66b9e398abe94c07f4b..b2bf03e3510b15e2cc8c2694e916b14fe85b273d 100644 --- a/test/java/nio/file/Path/Misc.java +++ b/test/java/nio/file/Path/Misc.java @@ -22,17 +22,13 @@ */ /* @test - * @bug 4313887 6838333 6867101 - * @summary Unit test for java.nio.file.Path for miscellenous methods not - * covered by other tests + * @bug 4313887 6838333 + * @summary Unit test for miscellenous java.nio.file.Path methods * @library .. */ import java.nio.file.*; -import static java.nio.file.LinkOption.*; -import java.nio.file.attribute.*; import java.io.*; -import java.util.*; public class Misc { static final boolean isWindows = @@ -45,22 +41,14 @@ public class Misc { supportsLinks = TestUtil.supportsLinks(dir); // equals and hashCode methods - equalsAndHashCode(); + testEqualsAndHashCode(); - // checkAccess method - checkAccessTests(dir); - - // getFileAttributeView methods - getFileAttributeViewTests(dir); + // toFile method + testToFile(dir); // toRealPath method - toRealPathTests(dir); - - // isSameFile method - isSameFileTests(dir); + testToRealPath(dir); - // isHidden method - isHiddenTests(dir); } finally { TestUtil.removeAll(dir); @@ -70,8 +58,7 @@ public class Misc { /** * Exercise equals and hashCode methods */ - static void equalsAndHashCode() { - + static void testEqualsAndHashCode() { Path thisFile = Paths.get("this"); Path thatFile = Paths.get("that"); @@ -93,172 +80,25 @@ public class Misc { } /** - * Exercise checkAccess method - */ - static void checkAccessTests(Path dir) throws IOException { - final Path file = dir.resolve("foo").createFile(); - - /** - * Test: This directory should readable and writable - */ - dir.checkAccess(); - dir.checkAccess(AccessMode.READ); - dir.checkAccess(AccessMode.WRITE); - dir.checkAccess(AccessMode.READ, AccessMode.WRITE); - - /** - * Test: Check access to all files in all root directories. - * (A useful test on Windows for special files such as pagefile.sys) - */ - for (Path root: FileSystems.getDefault().getRootDirectories()) { - DirectoryStream stream; - try { - stream = root.newDirectoryStream(); - } catch (IOException x) { - continue; // skip root directories that aren't accessible - } - try { - for (Path entry: stream) { - try { - entry.checkAccess(); - } catch (AccessDeniedException ignore) { } - } - } finally { - stream.close(); - } - } - - /** - * Test: File does not exist - */ - Path doesNotExist = dir.resolve("thisDoesNotExists"); - try { - doesNotExist.checkAccess(); - throw new RuntimeException("NoSuchFileException expected"); - } catch (NoSuchFileException x) { - } - try { - doesNotExist.checkAccess(AccessMode.READ); - throw new RuntimeException("NoSuchFileException expected"); - } catch (NoSuchFileException x) { - } - try { - doesNotExist.checkAccess(AccessMode.WRITE); - throw new RuntimeException("NoSuchFileException expected"); - } catch (NoSuchFileException x) { - } - try { - doesNotExist.checkAccess(AccessMode.EXECUTE); - throw new RuntimeException("NoSuchFileException expected"); - } catch (NoSuchFileException x) { - } - - /** - * Test: Edit ACL to deny WRITE and EXECUTE - */ - AclFileAttributeView view = file - .getFileAttributeView(AclFileAttributeView.class); - if (view != null && - file.getFileStore().supportsFileAttributeView("acl")) - { - UserPrincipal owner = view.getOwner(); - List acl = view.getAcl(); - - // Insert entry to deny WRITE and EXECUTE - AclEntry entry = AclEntry.newBuilder() - .setType(AclEntryType.DENY) - .setPrincipal(owner) - .setPermissions(AclEntryPermission.WRITE_DATA, - AclEntryPermission.EXECUTE) - .build(); - acl.add(0, entry); - view.setAcl(acl); - - try { - file.checkAccess(AccessMode.WRITE); - throw new RuntimeException("AccessDeniedException expected"); - } catch (AccessDeniedException x) { - } - - try { - file.checkAccess(AccessMode.EXECUTE); - throw new RuntimeException("AccessDeniedException expected"); - } catch (AccessDeniedException x) { - } - - - // Restore ACL - acl.remove(0); - view.setAcl(acl); - } - - /** - * Test: Windows DOS read-only attribute - */ - if (isWindows) { - DosFileAttributeView dview = - file.getFileAttributeView(DosFileAttributeView.class); - dview.setReadOnly(true); - try { - file.checkAccess(AccessMode.WRITE); - throw new RuntimeException("AccessDeniedException expected"); - } catch (AccessDeniedException x) { - } - dview.setReadOnly(false); - - // Read-only attribute does not make direcory read-only - dview = dir.getFileAttributeView(DosFileAttributeView.class); - boolean save = dview.readAttributes().isReadOnly(); - dview.setReadOnly(true); - dir.checkAccess(AccessMode.WRITE); - dview.setReadOnly(save); - } - - /** - * Test: null - */ - try { - file.checkAccess((AccessMode)null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - - // clean-up - file.delete(); - } - - /** - * Exercise getFileAttributeFile methods + * Exercise toFile method */ - static void getFileAttributeViewTests(Path dir) { - assertTrue(dir.getFileAttributeView(BasicFileAttributeView.class) - instanceof BasicFileAttributeView); - assertTrue(dir.getFileAttributeView(BasicFileAttributeView.class, NOFOLLOW_LINKS) - instanceof BasicFileAttributeView); - assertTrue(dir.getFileAttributeView(BogusFileAttributeView.class) == null); - try { - dir.getFileAttributeView((Class)null); - } catch (NullPointerException ignore) { } - try { - dir.getFileAttributeView(BasicFileAttributeView.class, (LinkOption[])null); - } catch (NullPointerException ignore) { } - try { - dir.getFileAttributeView(BasicFileAttributeView.class, (LinkOption)null); - } catch (NullPointerException ignore) { } - + static void testToFile(Path dir) throws IOException { + File d = dir.toFile(); + assertTrue(d.toString().equals(dir.toString())); + assertTrue(d.toPath().equals(dir)); } - interface BogusFileAttributeView extends FileAttributeView { } /** * Exercise toRealPath method */ - static void toRealPathTests(Path dir) throws IOException { - final Path file = dir.resolve("foo").createFile(); + static void testToRealPath(Path dir) throws IOException { + final Path file = Files.createFile(dir.resolve("foo")); final Path link = dir.resolve("link"); /** - * Test: toRealPath(true) will access same file as toRealPath(false) + * Test: totRealPath(true) will access same file as toRealPath(false) */ - assertTrue(file.toRealPath(true).isSameFile(file.toRealPath(false))); + assertTrue(Files.isSameFile(file.toRealPath(true), file.toRealPath(false))); /** * Test: toRealPath should fail if file does not exist @@ -279,29 +119,27 @@ public class Misc { * Test: toRealPath(true) should resolve links */ if (supportsLinks) { - link.createSymbolicLink(file.toAbsolutePath()); + Files.createSymbolicLink(link, file.toAbsolutePath()); assertTrue(link.toRealPath(true).equals(file.toRealPath(true))); - link.delete(); + Files.delete(link); } - /** * Test: toRealPath(false) should not resolve links */ if (supportsLinks) { - link.createSymbolicLink(file.toAbsolutePath()); - assertTrue(link.toRealPath(false).getName().equals(link.getName())); - link.delete(); + Files.createSymbolicLink(link, file.toAbsolutePath()); + assertTrue(link.toRealPath(false).getFileName().equals(link.getFileName())); + Files.delete(link); } /** * Test: toRealPath(false) with broken link */ if (supportsLinks) { - Path broken = dir.resolve("doesNotExist"); - link.createSymbolicLink(broken); - assertTrue(link.toRealPath(false).getName().equals(link.getName())); - link.delete(); + Path broken = Files.createSymbolicLink(link, doesNotExist); + assertTrue(link.toRealPath(false).getFileName().equals(link.getFileName())); + Files.delete(link); } /** @@ -314,105 +152,13 @@ public class Misc { * Test: toRealPath should eliminate ".." when it doesn't follow a * symbolic link */ - Path subdir = dir.resolve("subdir").createDirectory(); + Path subdir = Files.createDirectory(dir.resolve("subdir")); assertTrue(subdir.resolve("..").toRealPath(true).equals(dir.toRealPath(true))); assertTrue(subdir.resolve("..").toRealPath(false).equals(dir.toRealPath(false))); - subdir.delete(); + Files.delete(subdir); // clean-up - file.delete(); - } - - /** - * Exercise isSameFile method - */ - static void isSameFileTests(Path dir) throws IOException { - Path thisFile = dir.resolve("thisFile"); - Path thatFile = dir.resolve("thatFile"); - - /** - * Test: isSameFile for self and null - */ - assertTrue(thisFile.isSameFile(thisFile)); - assertTrue(!thisFile.isSameFile(null)); - - /** - * Test: Neither files exist - */ - try { - thisFile.isSameFile(thatFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } - try { - thatFile.isSameFile(thisFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } - - thisFile.createFile(); - try { - /** - * Test: One file exists - */ - try { - thisFile.isSameFile(thatFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } - try { - thatFile.isSameFile(thisFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } - - thatFile.createFile(); - - /** - * Test: Both file exists - */ - try { - assertTrue(!thisFile.isSameFile(thatFile)); - assertTrue(!thatFile.isSameFile(thisFile)); - } finally { - TestUtil.deleteUnchecked(thatFile); - } - - /** - * Test: Symbolic links - */ - if (supportsLinks) { - thatFile.createSymbolicLink(thisFile); - try { - assertTrue(thisFile.isSameFile(thatFile)); - assertTrue(thatFile.isSameFile(thisFile)); - } finally { - TestUtil.deleteUnchecked(thatFile); - } - } - } finally { - thisFile.delete(); - } - } - - /** - * Exercise isHidden method - */ - static void isHiddenTests(Path dir) throws IOException { - assertTrue(!dir.isHidden()); - - Path file = dir.resolve(".foo"); - if (isWindows) { - file.createFile(); - try { - file.setAttribute("dos:hidden", true); - assertTrue(file.isHidden()); - } finally { - file.delete(); - } - } else { - assertTrue(file.isHidden()); - } + Files.delete(file); } static void assertTrue(boolean okay) { diff --git a/test/java/nio/file/Path/PathOps.java b/test/java/nio/file/Path/PathOps.java index fcc02e61a44baf0ba4129fa1acd39a3edb757b55..00264201201408ce33b2aa6a501be5d5018c2b6e 100644 --- a/test/java/nio/file/Path/PathOps.java +++ b/test/java/nio/file/Path/PathOps.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6925932 + * @bug 4313887 6838333 6925932 7006126 * @summary Unit test for java.nio.file.Path path operations */ @@ -36,15 +36,15 @@ public class PathOps { private Path path; private Exception exc; - private PathOps(String s) { + private PathOps(String first, String... more) { out.println(); - input = s; + input = first; try { - path = FileSystems.getDefault().getPath(s); - out.format("%s -> %s", s, path); + path = FileSystems.getDefault().getPath(first, more); + out.format("%s -> %s", first, path); } catch (Exception x) { exc = x; - out.format("%s -> %s", s, x); + out.format("%s -> %s", first, x); } out.println(); } @@ -97,7 +97,7 @@ public class PathOps { PathOps name(String expected) { out.println("check name"); checkPath(); - check(path.getName(), expected); + check(path.getFileName(), expected); return this; } @@ -168,6 +168,13 @@ public class PathOps { return this; } + PathOps resolveSibling(String other, String expected) { + out.format("test resolveSibling %s\n", other); + checkPath(); + check(path.resolveSibling(other), expected); + return this; + } + PathOps relativize(String other, String expected) { out.format("test relativize %s\n", other); checkPath(); @@ -198,8 +205,8 @@ public class PathOps { return this; } - static PathOps test(String s) { - return new PathOps(s); + static PathOps test(String first, String... more) { + return new PathOps(first, more); } // -- PathOpss -- @@ -213,6 +220,26 @@ public class PathOps { static void doWindowsTests() { header("Windows specific tests"); + // construction + test("C:\\") + .string("C:\\"); + test("C:\\", "") + .string("C:\\"); + test("C:\\", "foo") + .string("C:\\foo"); + test("C:\\", "\\foo") + .string("C:\\foo"); + test("C:\\", "foo\\") + .string("C:\\foo"); + test("foo", "bar", "gus") + .string("foo\\bar\\gus"); + test("") + .string(""); + test("", "C:\\") + .string("C:\\"); + test("", "foo", "", "bar", "", "\\gus") + .string("foo\\bar\\gus"); + // all components present test("C:\\a\\b\\c") .root("C:\\") @@ -252,17 +279,23 @@ public class PathOps { .root(null) .parent(null) .name("foo"); + test("") + .root(null) + .parent(null) + .name(""); // startsWith test("C:\\") .starts("C:\\") .starts("c:\\") .notStarts("C") - .notStarts("C:"); + .notStarts("C:") + .notStarts(""); test("C:") .starts("C:") .starts("c:") - .notStarts("C"); + .notStarts("C") + .notStarts(""); test("\\") .starts("\\"); test("C:\\foo\\bar") @@ -273,7 +306,8 @@ public class PathOps { .starts("C:\\Foo\\Bar") .notStarts("C:") .notStarts("C") - .notStarts("C:foo"); + .notStarts("C:foo") + .notStarts(""); test("\\foo\\bar") .starts("\\") .starts("\\foo") @@ -281,26 +315,35 @@ public class PathOps { .starts("\\foo\\bar") .starts("\\fOo\\BaR") .notStarts("foo") - .notStarts("foo\\bar"); + .notStarts("foo\\bar") + .notStarts(""); test("foo\\bar") .starts("foo") .starts("foo\\bar") - .notStarts("\\"); + .notStarts("\\") + .notStarts(""); test("\\\\server\\share") .starts("\\\\server\\share") .starts("\\\\server\\share\\") + .notStarts("\\") + .notStarts(""); + test("") + .starts("") .notStarts("\\"); // endsWith test("C:\\") .ends("C:\\") .ends("c:\\") - .notEnds("\\"); + .notEnds("\\") + .notEnds(""); test("C:") .ends("C:") - .ends("c:"); + .ends("c:") + .notEnds(""); test("\\") - .ends("\\"); + .ends("\\") + .notEnds(""); test("C:\\foo\\bar") .ends("bar") .ends("BAR") @@ -309,7 +352,8 @@ public class PathOps { .ends("C:\\foo\\bar") .ends("c:\\foO\\baR") .notEnds("r") - .notEnds("\\foo\\bar"); + .notEnds("\\foo\\bar") + .notEnds(""); test("\\foo\\bar") .ends("bar") .ends("BaR") @@ -317,17 +361,23 @@ public class PathOps { .ends("foO\\baR") .ends("\\foo\\bar") .ends("\\Foo\\Bar") - .notEnds("oo\\bar"); + .notEnds("oo\\bar") + .notEnds(""); test("foo\\bar") .ends("bar") .ends("BAR") .ends("foo\\bar") .ends("Foo\\Bar") - .notEnds("ar"); + .notEnds("ar") + .notEnds(""); test("\\\\server\\share") .ends("\\\\server\\share") .ends("\\\\server\\share\\") .notEnds("shared") + .notEnds("\\") + .notEnds(""); + test("") + .ends("") .notEnds("\\"); // elements @@ -338,6 +388,8 @@ public class PathOps { test("foo.bar\\gus.alice") .element(0, "foo.bar") .element(1, "gus.alice"); + test("") + .element(0, ""); // subpath test("C:\\foo") @@ -355,6 +407,8 @@ public class PathOps { .subpath(2, 3, "gus"); test("\\\\server\\share\\foo") .subpath(0, 1, "foo"); + test("") + .subpath(0, 1, ""); // isAbsolute test("foo").notAbsolute(); @@ -362,6 +416,7 @@ public class PathOps { test("C:\\").absolute(); test("C:\\abc").absolute(); test("\\\\server\\share\\").absolute(); + test("").notAbsolute(); // resolve test("C:\\") @@ -369,42 +424,99 @@ public class PathOps { .resolve("D:\\bar", "D:\\bar") .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar") .resolve("C:foo", "C:\\foo") - .resolve("D:foo", "D:foo"); + .resolve("D:foo", "D:foo") + .resolve("", "C:\\"); test("\\") .resolve("foo", "\\foo") .resolve("D:bar", "D:bar") .resolve("C:\\bar", "C:\\bar") .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar") - .resolve("\\foo", "\\foo"); + .resolve("\\foo", "\\foo") + .resolve("", "\\"); test("\\foo") .resolve("bar", "\\foo\\bar") .resolve("D:bar", "D:bar") .resolve("C:\\bar", "C:\\bar") .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar") - .resolve("\\bar", "\\bar"); + .resolve("\\bar", "\\bar") + .resolve("", "\\foo"); test("foo") .resolve("bar", "foo\\bar") .resolve("D:\\bar", "D:\\bar") .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar") .resolve("C:bar", "C:bar") - .resolve("D:foo", "D:foo"); + .resolve("D:foo", "D:foo") + .resolve("", "foo"); test("C:") - .resolve("foo", "C:foo"); + .resolve("foo", "C:foo") + .resolve("", "C:"); test("\\\\server\\share\\foo") .resolve("bar", "\\\\server\\share\\foo\\bar") .resolve("\\bar", "\\\\server\\share\\bar") .resolve("D:\\bar", "D:\\bar") .resolve("\\\\other\\share\\bar", "\\\\other\\share\\bar") - .resolve("D:bar", "D:bar"); + .resolve("D:bar", "D:bar") + .resolve("", "\\\\server\\share\\foo"); + test("") + .resolve("", "") + .resolve("foo", "foo") + .resolve("C:\\", "C:\\") + .resolve("C:foo", "C:foo") + .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar"); + + // resolveSibling + test("foo") + .resolveSibling("bar", "bar") + .resolveSibling("D:\\bar", "D:\\bar") + .resolveSibling("\\\\server\\share\\bar", "\\\\server\\share\\bar") + .resolveSibling("C:bar", "C:bar") + .resolveSibling("D:foo", "D:foo") + .resolveSibling("", ""); + test("foo\\bar") + .resolveSibling("gus", "foo\\gus") + .resolveSibling("D:\\bar", "D:\\bar") + .resolveSibling("\\\\server\\share\\bar", "\\\\server\\share\\bar") + .resolveSibling("C:bar", "C:bar") + .resolveSibling("D:foo", "D:foo") + .resolveSibling("", "foo"); + test("C:\\foo") + .resolveSibling("gus", "C:\\gus") + .resolveSibling("D:\\bar", "D:\\bar") + .resolveSibling("\\\\server\\share\\bar", "\\\\server\\share\\bar") + .resolveSibling("C:bar", "C:\\bar") + .resolveSibling("D:foo", "D:foo") + .resolveSibling("", "C:\\"); + test("C:\\foo\\bar") + .resolveSibling("gus", "C:\\foo\\gus") + .resolveSibling("D:\\bar", "D:\\bar") + .resolveSibling("\\\\server\\share\\bar", "\\\\server\\share\\bar") + .resolveSibling("C:bar", "C:\\foo\\bar") + .resolveSibling("D:foo", "D:foo") + .resolveSibling("", "C:\\foo"); + test("\\\\server\\share\\foo") + .resolveSibling("bar", "\\\\server\\share\\bar") + .resolveSibling("\\bar", "\\\\server\\share\\bar") + .resolveSibling("D:\\bar", "D:\\bar") + .resolveSibling("\\\\other\\share\\bar", "\\\\other\\share\\bar") + .resolveSibling("D:bar", "D:bar") + .resolveSibling("", "\\\\server\\share\\"); + test("") + .resolveSibling("", "") + .resolveSibling("foo", "foo") + .resolveSibling("C:\\", "C:\\"); // relativize test("foo\\bar") - .relativize("foo\\bar", null) + .relativize("foo\\bar", "") .relativize("foo", ".."); test("C:\\a\\b\\c") - .relativize("C:\\a", "..\\.."); + .relativize("C:\\a", "..\\..") + .relativize("C:\\a\\b\\c", ""); test("\\\\server\\share\\foo") - .relativize("\\\\server\\share\\bar", "..\\bar"); + .relativize("\\\\server\\share\\bar", "..\\bar") + .relativize("\\\\server\\share\\foo", ""); + test("") + .relativize("", ""); // normalize test("C:\\") @@ -436,7 +548,7 @@ public class PathOps { test("foo\\.") .normalize("foo"); test("foo\\..") - .normalize(null); + .normalize(""); test("C:\\foo") .normalize("C:\\foo"); test("C:\\foo\\.") @@ -478,7 +590,7 @@ public class PathOps { test("\\..\\foo") .normalize("\\foo"); test(".") - .normalize(null); + .normalize(""); test("..") .normalize(".."); test("\\..\\..") @@ -493,6 +605,8 @@ public class PathOps { .normalize("foo"); test(".\\foo\\.\\bar\\.\\gus\\..\\.\\..") .normalize("foo"); + test("") + .normalize(""); // UNC corner cases test("\\\\server\\share\\") @@ -557,6 +671,26 @@ public class PathOps { static void doUnixTests() { header("Unix specific tests"); + // construction + test("/") + .string("/"); + test("/", "") + .string("/"); + test("/", "foo") + .string("/foo"); + test("/", "/foo") + .string("/foo"); + test("/", "foo/") + .string("/foo"); + test("foo", "bar", "gus") + .string("foo/bar/gus"); + test("") + .string(""); + test("", "/") + .string("/"); + test("", "foo", "", "bar", "", "/gus") + .string("foo/bar/gus"); + // all components test("/a/b/c") .root("/") @@ -580,10 +714,15 @@ public class PathOps { .root(null) .parent(null) .name("foo"); + test("") + .root(null) + .parent(null) + .name(""); // startsWith test("/") .starts("/") + .notStarts("") .notStarts("/foo"); test("/foo") .starts("/") @@ -598,6 +737,7 @@ public class PathOps { .notStarts("foo/bar"); test("foo") .starts("foo") + .notStarts("") .notStarts("f"); test("foo/bar") .starts("foo") @@ -605,10 +745,14 @@ public class PathOps { .notStarts("f") .notStarts("/foo") .notStarts("/foo/bar"); + test("") + .starts("") + .notStarts("/"); // endsWith test("/") .ends("/") + .notEnds("") .notEnds("foo") .notEnds("/foo"); test("/foo") @@ -625,6 +769,7 @@ public class PathOps { .notEnds("o/bar"); test("foo") .ends("foo") + .notEnds("") .notEnds("oo") .notEnds("oola"); test("foo/bar") @@ -642,12 +787,47 @@ public class PathOps { .notEnds("r/gus") .notEnds("barack/gus") .notEnds("bar/gust"); + test("") + .ends("") + .notEnds("/"); // elements test("a/b/c") - .element(0,"a") - .element(1,"b") - .element(2,"c"); + .element(0, "a") + .element(1, "b") + .element(2, "c"); + test("") + .element(0, ""); + + // subpath + test("/foo") + .subpath(0, 1, "foo"); + test("foo") + .subpath(0, 1, "foo"); + test("/foo/bar") + .subpath(0, 1, "foo") + .subpath(1, 2, "bar") + .subpath(0, 2, "foo/bar"); + test("foo/bar") + .subpath(0, 1, "foo") + .subpath(1, 2, "bar") + .subpath(0, 2, "foo/bar"); + test("/foo/bar/gus") + .subpath(0, 1, "foo") + .subpath(1, 2, "bar") + .subpath(2, 3, "gus") + .subpath(0, 2, "foo/bar") + .subpath(1, 3, "bar/gus") + .subpath(0, 3, "foo/bar/gus"); + test("foo/bar/gus") + .subpath(0, 1, "foo") + .subpath(1, 2, "bar") + .subpath(2, 3, "gus") + .subpath(0, 2, "foo/bar") + .subpath(1, 3, "bar/gus") + .subpath(0, 3, "foo/bar/gus"); + test("") + .subpath(0, 1, ""); // isAbsolute test("/") @@ -656,20 +836,61 @@ public class PathOps { .absolute(); test("tmp") .notAbsolute(); + test("") + .notAbsolute(); + // resolve test("/tmp") .resolve("foo", "/tmp/foo") - .resolve("/foo", "/foo"); + .resolve("/foo", "/foo") + .resolve("", "/tmp"); test("tmp") .resolve("foo", "tmp/foo") + .resolve("/foo", "/foo") + .resolve("", "tmp"); + test("") + .resolve("", "") + .resolve("foo", "foo") .resolve("/foo", "/foo"); + // resolveSibling + test("foo") + .resolveSibling("bar", "bar") + .resolveSibling("/bar", "/bar") + .resolveSibling("", ""); + test("foo/bar") + .resolveSibling("gus", "foo/gus") + .resolveSibling("/gus", "/gus") + .resolveSibling("", "foo"); + test("/foo") + .resolveSibling("gus", "/gus") + .resolveSibling("/gus", "/gus") + .resolveSibling("", "/"); + test("/foo/bar") + .resolveSibling("gus", "/foo/gus") + .resolveSibling("/gus", "/gus") + .resolveSibling("", "/foo"); + test("") + .resolveSibling("foo", "foo") + .resolveSibling("/foo", "/foo") + .resolve("", ""); + // relativize test("/a/b/c") - .relativize("/a/b/c", null) + .relativize("/a/b/c", "") .relativize("/a/b/c/d/e", "d/e") - .relativize("/a/x", "../../x"); + .relativize("/a/x", "../../x") + .relativize("/x", "../../../x"); + test("a/b/c") + .relativize("a/b/c/d", "d") + .relativize("a/x", "../../x") + .relativize("x", "../../../x") + .relativize("", "../../.."); + test("") + .relativize("a", "a") + .relativize("a/b/c", "a/b/c") + .relativize("", ""); // normalize test("/") @@ -679,7 +900,7 @@ public class PathOps { test("/foo") .normalize("/foo"); test(".") - .normalize(null); + .normalize(""); test("..") .normalize(".."); test("/..") @@ -691,7 +912,7 @@ public class PathOps { test("./foo") .normalize("foo"); test("foo/..") - .normalize(null); + .normalize(""); test("../foo") .normalize("../foo"); test("../../foo") @@ -717,7 +938,7 @@ public class PathOps { test("//bar\u0000") .invalid(); - // normalization + // normalization of input test("//foo//bar") .string("/foo/bar") .root("/") @@ -749,13 +970,13 @@ public class PathOps { } try { - path.startsWith(null); + path.startsWith((Path)null); throw new RuntimeException("NullPointerException not thrown"); } catch (NullPointerException npe) { } try { - path.endsWith(null); + path.endsWith((Path)null); throw new RuntimeException("NullPointerException not thrown"); } catch (NullPointerException npe) { } diff --git a/test/java/nio/file/Path/TemporaryFiles.java b/test/java/nio/file/Path/TemporaryFiles.java deleted file mode 100644 index e7603bf630ea3e34099961785e3e8eb86e3d82b9..0000000000000000000000000000000000000000 --- a/test/java/nio/file/Path/TemporaryFiles.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 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 4313887 6838333 - * @summary Unit test for File.createTemporaryXXX (to be be moved to test/java/io/File) - * @library .. - */ - -import java.nio.file.*; -import static java.nio.file.StandardOpenOption.*; -import java.nio.file.attribute.*; -import java.io.File; -import java.io.IOException; -import java.util.Set; - -public class TemporaryFiles { - - static void checkInTempDirectory(Path file) { - Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); - if (!file.getParent().equals(tmpdir)) - throw new RuntimeException("Not in temporary directory"); - } - - static void checkFile(Path file) throws IOException { - // check file is in temporary directory - checkInTempDirectory(file); - - // check that file can be opened for reading and writing - file.newByteChannel(READ).close(); - file.newByteChannel(WRITE).close(); - file.newByteChannel(READ,WRITE).close(); - - // check file permissions are 0600 or more secure - if (file.getFileStore().supportsFileAttributeView("posix")) { - Set perms = Attributes - .readPosixFileAttributes(file).permissions(); - perms.remove(PosixFilePermission.OWNER_READ); - perms.remove(PosixFilePermission.OWNER_WRITE); - if (!perms.isEmpty()) - throw new RuntimeException("Temporary file is not secure"); - } - } - - static void checkDirectory(Path dir) throws IOException { - // check directory is in temporary directory - checkInTempDirectory(dir); - - // check directory is empty - DirectoryStream stream = dir.newDirectoryStream(); - try { - if (stream.iterator().hasNext()) - throw new RuntimeException("Tempory directory not empty"); - } finally { - stream.close(); - } - - // check file permissions are 0700 or more secure - if (dir.getFileStore().supportsFileAttributeView("posix")) { - Set perms = Attributes - .readPosixFileAttributes(dir).permissions(); - perms.remove(PosixFilePermission.OWNER_READ); - perms.remove(PosixFilePermission.OWNER_WRITE); - perms.remove(PosixFilePermission.OWNER_EXECUTE); - if (!perms.isEmpty()) - throw new RuntimeException("Temporary directory is not secure"); - } - } - - public static void main(String[] args) throws IOException { - Path file = File.createTemporaryFile("blah", null).toPath(); - try { - checkFile(file); - } finally { - TestUtil.deleteUnchecked(file); - } - } -} diff --git a/test/java/nio/file/TestUtil.java b/test/java/nio/file/TestUtil.java index b0fdd2a1f9d2f9d90beef6e436e30bffe0250c6a..f77d8f1adb34f04189313cca88a3d462137e87b3 100644 --- a/test/java/nio/file/TestUtil.java +++ b/test/java/nio/file/TestUtil.java @@ -31,17 +31,12 @@ public class TestUtil { } static Path createTemporaryDirectory(String where) throws IOException { - Path top = FileSystems.getDefault().getPath(where); - Random r = new Random(); - Path dir; - do { - dir = top.resolve("name" + r.nextInt()); - } while (dir.exists()); - return dir.createDirectory(); + Path dir = FileSystems.getDefault().getPath(where); + return Files.createTempDirectory(dir, "name"); } static Path createTemporaryDirectory() throws IOException { - return createTemporaryDirectory(System.getProperty("java.io.tmpdir")); + return Files.createTempDirectory("name"); } static void removeAll(Path dir) throws IOException { @@ -53,7 +48,7 @@ public class TestUtil { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { try { - file.delete(); + Files.delete(file); } catch (IOException x) { System.err.format("Unable to delete %s: %s\n", file, x); } @@ -62,7 +57,7 @@ public class TestUtil { @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { try { - dir.delete(); + Files.delete(dir); } catch (IOException x) { System.err.format("Unable to delete %s: %s\n", dir, x); } @@ -78,7 +73,7 @@ public class TestUtil { static void deleteUnchecked(Path file) { try { - file.delete(); + Files.delete(file); } catch (IOException exc) { System.err.format("Unable to delete %s: %s\n", file, exc); } @@ -99,7 +94,7 @@ public class TestUtil { String name = sb.toString(); do { dir = dir.resolve(name).resolve("."); - dir.createDirectory(); + Files.createDirectory(dir); } while (dir.toString().length() < 2048); return dir; } @@ -111,8 +106,8 @@ public class TestUtil { Path link = dir.resolve("testlink"); Path target = dir.resolve("testtarget"); try { - link.createSymbolicLink(target); - link.delete(); + Files.createSymbolicLink(link, target); + Files.delete(link); return true; } catch (UnsupportedOperationException x) { return false; diff --git a/test/java/nio/file/WatchService/Basic.java b/test/java/nio/file/WatchService/Basic.java index 104781410aeb86352055214022711ec2cb8551b9..2869a519f376961c9d9a15a0dbe807f4d510d542 100644 --- a/test/java/nio/file/WatchService/Basic.java +++ b/test/java/nio/file/WatchService/Basic.java @@ -41,8 +41,9 @@ import java.util.concurrent.TimeUnit; public class Basic { - static void createFile(Path file) throws IOException { - file.newOutputStream().close(); + static void checkKey(WatchKey key, Path dir) { + if (!key.isValid()) + throw new RuntimeException("Key is not valid"); } static void takeExpectedKey(WatchService watcher, WatchKey expected) { @@ -80,19 +81,19 @@ public class Basic { FileSystem fs = FileSystems.getDefault(); Path name = fs.getPath("foo"); - WatchService watcher = fs.newWatchService(); - try { + try (WatchService watcher = fs.newWatchService()) { // --- ENTRY_CREATE --- // register for event System.out.format("register %s for ENTRY_CREATE\n", dir); WatchKey myKey = dir.register(watcher, new WatchEvent.Kind[]{ ENTRY_CREATE }); + checkKey(myKey, dir); // create file Path file = dir.resolve("foo"); System.out.format("create %s\n", file); - createFile(file); + Files.createFile(file); // remove key and check that we got the ENTRY_CREATE event takeExpectedKey(watcher, myKey); @@ -112,9 +113,10 @@ public class Basic { new WatchEvent.Kind[]{ ENTRY_DELETE }); if (deleteKey != myKey) throw new RuntimeException("register did not return existing key"); + checkKey(deleteKey, dir); System.out.format("delete %s\n", file); - file.delete(); + Files.delete(file); takeExpectedKey(watcher, myKey); checkExpectedEvent(myKey.pollEvents(), StandardWatchEventKind.ENTRY_DELETE, name); @@ -126,7 +128,7 @@ public class Basic { System.out.println("OKAY"); // create the file for the next test - createFile(file); + Files.createFile(file); // --- ENTRY_MODIFY --- @@ -135,13 +137,11 @@ public class Basic { new WatchEvent.Kind[]{ ENTRY_MODIFY }); if (newKey != myKey) throw new RuntimeException("register did not return existing key"); + checkKey(newKey, dir); System.out.format("update: %s\n", file); - OutputStream out = file.newOutputStream(StandardOpenOption.APPEND); - try { + try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.APPEND)) { out.write("I am a small file".getBytes("UTF-8")); - } finally { - out.close(); } // remove key and check that we got the ENTRY_MODIFY event @@ -151,10 +151,7 @@ public class Basic { System.out.println("OKAY"); // done - file.delete(); - - } finally { - watcher.close(); + Files.delete(file); } } @@ -164,12 +161,12 @@ public class Basic { static void testCancel(Path dir) throws IOException { System.out.println("-- Cancel --"); - WatchService watcher = FileSystems.getDefault().newWatchService(); - try { + try (WatchService watcher = FileSystems.getDefault().newWatchService()) { System.out.format("register %s for events\n", dir); WatchKey myKey = dir.register(watcher, new WatchEvent.Kind[]{ ENTRY_CREATE }); + checkKey(myKey, dir); System.out.println("cancel key"); myKey.cancel(); @@ -177,7 +174,7 @@ public class Basic { // create a file in the directory Path file = dir.resolve("mars"); System.out.format("create: %s\n", file); - createFile(file); + Files.createFile(file); // poll for keys - there will be none System.out.println("poll..."); @@ -190,12 +187,9 @@ public class Basic { } // done - file.delete(); + Files.delete(file); System.out.println("OKAY"); - - } finally { - watcher.close(); } } @@ -206,17 +200,16 @@ public class Basic { static void testAutomaticCancel(Path dir) throws IOException { System.out.println("-- Automatic Cancel --"); - Path subdir = dir.resolve("bar").createDirectory(); + Path subdir = Files.createDirectory(dir.resolve("bar")); - WatchService watcher = FileSystems.getDefault().newWatchService(); - try { + try (WatchService watcher = FileSystems.getDefault().newWatchService()) { System.out.format("register %s for events\n", subdir); WatchKey myKey = subdir.register(watcher, new WatchEvent.Kind[]{ ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY }); System.out.format("delete: %s\n", subdir); - subdir.delete(); + Files.delete(subdir); takeExpectedKey(watcher, myKey); System.out.println("reset key"); @@ -227,8 +220,6 @@ public class Basic { System.out.println("OKAY"); - } finally { - watcher.close(); } } @@ -411,7 +402,7 @@ public class Basic { // create gus1 Path file1 = dir.resolve(name1); System.out.format("create %s\n", file1); - createFile(file1); + Files.createFile(file1); // register with both watch services (different events) System.out.println("register for different events"); @@ -426,7 +417,7 @@ public class Basic { // create gus2 Path file2 = dir.resolve(name2); System.out.format("create %s\n", file2); - createFile(file2); + Files.createFile(file2); // check that key1 got ENTRY_CREATE takeExpectedKey(watcher1, key1); @@ -439,7 +430,7 @@ public class Basic { throw new RuntimeException("key not expected"); // delete gus1 - file1.delete(); + Files.delete(file1); // check that key2 got ENTRY_DELETE takeExpectedKey(watcher2, key2); @@ -462,7 +453,7 @@ public class Basic { // create file and key2 should be queued System.out.format("create %s\n", file1); - createFile(file1); + Files.createFile(file1); takeExpectedKey(watcher2, key2); checkExpectedEvent(key2.pollEvents(), StandardWatchEventKind.ENTRY_CREATE, name1); diff --git a/test/java/nio/file/WatchService/FileTreeModifier.java b/test/java/nio/file/WatchService/FileTreeModifier.java index 01db8b97a404fd58933fd9239de020607f68290a..cde17db11247d9b3d7b19eb8aa7c67a9826e9d87 100644 --- a/test/java/nio/file/WatchService/FileTreeModifier.java +++ b/test/java/nio/file/WatchService/FileTreeModifier.java @@ -62,10 +62,7 @@ public class FileTreeModifier { WatchService watcher = fs.newWatchService(); // create directories - Path subdir = top - .resolve("a").createDirectory() - .resolve("b").createDirectory() - .resolve("c").createDirectory(); + Path subdir = Files.createDirectories(top.resolve("a").resolve("b").resolve("c")); // Test ENTRY_CREATE with FILE_TREE modifier. @@ -73,7 +70,7 @@ public class FileTreeModifier { new WatchEvent.Kind[]{ ENTRY_CREATE }, FILE_TREE); // create file in a/b/c and check we get create event - Path file = subdir.resolve("foo").createFile(); + Path file = Files.createFile(subdir.resolve("foo")); checkExpectedEvent(watcher, ENTRY_CREATE, top.relativize(file)); key.reset(); @@ -85,7 +82,7 @@ public class FileTreeModifier { throw new RuntimeException("Existing key not returned"); // delete a/b/c/foo and check we get delete event - file.delete(); + Files.delete(file); checkExpectedEvent(watcher, ENTRY_DELETE, top.relativize(file)); key.reset(); @@ -96,19 +93,20 @@ public class FileTreeModifier { throw new RuntimeException("Existing key not returned"); // create a/b/c/foo - file.createFile(); + Files.createFile(file); // check that key is not queued + WatchKey nextKey; try { - k = watcher.poll(3, TimeUnit.SECONDS); + nextKey = watcher.poll(3, TimeUnit.SECONDS); } catch (InterruptedException e) { throw new RuntimeException(); } - if (k != null) + if (nextKey != null) throw new RuntimeException("WatchKey not expected to be polled"); // create bar and check we get create event - file = top.resolve("bar").createFile(); + file = Files.createFile(top.resolve("bar")); checkExpectedEvent(watcher, ENTRY_CREATE, top.relativize(file)); key.reset(); @@ -121,11 +119,8 @@ public class FileTreeModifier { throw new RuntimeException("Existing key not returned"); // modify bar and check we get modify event - OutputStream out = file.newOutputStream(); - try { + try (OutputStream out = Files.newOutputStream(file)) { out.write("Double shot expresso please".getBytes("UTF-8")); - } finally { - out.close(); } checkExpectedEvent(watcher, ENTRY_MODIFY, top.relativize(file)); key.reset(); diff --git a/test/java/nio/file/WatchService/LotsOfEvents.java b/test/java/nio/file/WatchService/LotsOfEvents.java index c19e7d50a0a22b8138f3fa5527669869441b6e24..96fb4d81783a09c4204121c7e5f03f756071dee7 100644 --- a/test/java/nio/file/WatchService/LotsOfEvents.java +++ b/test/java/nio/file/WatchService/LotsOfEvents.java @@ -55,15 +55,14 @@ public class LotsOfEvents { static void testOverflowEvent(Path dir) throws IOException, InterruptedException { - WatchService watcher = dir.getFileSystem().newWatchService(); - try { + try (WatchService watcher = dir.getFileSystem().newWatchService()) { dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE); // create a lot of files int n = 1024; Path[] files = new Path[n]; for (int i=0; i modified = new HashSet(); + Set modified = new HashSet<>(); for (WatchEvent event: key.pollEvents()) { WatchEvent.Kind kind = event.kind(); Path file = (kind == OVERFLOW) ? null : (Path)event.context(); @@ -188,9 +184,6 @@ public class LotsOfEvents { key = watcher.poll(2, TimeUnit.SECONDS); } } - - } finally { - watcher.close(); } } @@ -200,20 +193,17 @@ public class LotsOfEvents { this.file = file; } void create() throws IOException { - if (file.notExists()) - file.createFile(); + if (Files.notExists(file)) + Files.createFile(file); } void deleteIfExists() throws IOException { - file.deleteIfExists(); + Files.deleteIfExists(file); } void modifyIfExists() throws IOException { - if (file.exists()) { - OutputStream out = file.newOutputStream(StandardOpenOption.APPEND); - try { + if (Files.exists(file)) { + try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.APPEND)) { out.write("message".getBytes()); - } finally { - out.close(); } } } diff --git a/test/java/nio/file/WatchService/SensitivityModifier.java b/test/java/nio/file/WatchService/SensitivityModifier.java index 63b26f9d51f76daeb47cb7183163da4bd9b3f832..47ff2b69bcffb0be2a43069ac925fbe48ea9aaf3 100644 --- a/test/java/nio/file/WatchService/SensitivityModifier.java +++ b/test/java/nio/file/WatchService/SensitivityModifier.java @@ -51,6 +51,7 @@ public class SensitivityModifier { } } + @SuppressWarnings("unchecked") static void doTest(Path top) throws Exception { FileSystem fs = top.getFileSystem(); WatchService watcher = fs.newWatchService(); @@ -61,11 +62,11 @@ public class SensitivityModifier { Path[] dirs = new Path[nDirs]; Path[] files = new Path[nFiles]; for (int i=0; i)event).context(); - if (!name.equals(file.getName())) + if (!name.equals(file.getFileName())) throw new RuntimeException("Unexpected context: " + name); System.out.println("Event OK"); diff --git a/test/java/nio/file/attribute/AclFileAttributeView/Basic.java b/test/java/nio/file/attribute/AclFileAttributeView/Basic.java index 03a0e48e783a3768680b89f22e1e9622126cdbff..bc32699cbfaa48cd511cd76c77d9c14924141fd2 100644 --- a/test/java/nio/file/attribute/AclFileAttributeView/Basic.java +++ b/test/java/nio/file/attribute/AclFileAttributeView/Basic.java @@ -47,11 +47,11 @@ public class Basic { // sanity check read and writing ACL static void testReadWrite(Path dir) throws IOException { Path file = dir.resolve("foo"); - if (file.notExists()) - file.createFile(); + if (Files.notExists(file)) + Files.createFile(file); - AclFileAttributeView view = file - .getFileAttributeView(AclFileAttributeView.class); + AclFileAttributeView view = + Files.getFileAttributeView(file, AclFileAttributeView.class); // print existing ACL List acl = view.getAcl(); @@ -79,7 +79,7 @@ public class Basic { } // if PosixFileAttributeView then repeat test with OWNER@ - if (file.getFileStore().supportsFileAttributeView("posix")) { + if (Files.getFileStore(file).supportsFileAttributeView("posix")) { owner = file.getFileSystem().getUserPrincipalLookupService() .lookupPrincipalByName("OWNER@"); entry = AclEntry.newBuilder(entry).setPrincipal(owner).build(); @@ -115,7 +115,8 @@ public class Basic { // sanity check create a file or directory with initial ACL static void testCreateFile(Path dir) throws IOException { - UserPrincipal user = Attributes.getOwner(dir); + UserPrincipal user = Files.getOwner(dir); + AclFileAttributeView view; // create file with initial ACL System.out.println("-- create file with initial ACL --"); @@ -127,8 +128,9 @@ public class Basic { .setPermissions(SYNCHRONIZE, READ_DATA, WRITE_DATA, READ_ATTRIBUTES, READ_ACL, WRITE_ATTRIBUTES, DELETE) .build()); - file.createFile(asAclAttribute(fileAcl)); - assertEquals(Attributes.getAcl(file), fileAcl); + Files.createFile(file, asAclAttribute(fileAcl)); + view = Files.getFileAttributeView(file, AclFileAttributeView.class); + assertEquals(view.getAcl(), fileAcl); // create directory with initial ACL System.out.println("-- create directory with initial ACL --"); @@ -142,17 +144,18 @@ public class Basic { AclEntry.newBuilder(fileAcl.get(0)) .setFlags(FILE_INHERIT) .build()); - subdir.createDirectory(asAclAttribute(dirAcl)); - assertEquals(Attributes.getAcl(subdir), dirAcl); + Files.createDirectory(subdir, asAclAttribute(dirAcl)); + view = Files.getFileAttributeView(subdir, AclFileAttributeView.class); + assertEquals(view.getAcl(), dirAcl); } public static void main(String[] args) throws IOException { // use work directory rather than system temporary directory to // improve chances that ACLs are supported - Path dir = Paths.get("./work" + new Random().nextInt()) - .createDirectory(); + Path dir = Paths.get("./work" + new Random().nextInt()); + Files.createDirectory(dir); try { - if (!dir.getFileStore().supportsFileAttributeView("acl")) { + if (!Files.getFileStore(dir).supportsFileAttributeView("acl")) { System.out.println("ACLs not supported - test skipped!"); return; } diff --git a/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java b/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java index c2cb23a4ff6960eba3aca72e3d54691c1e2289c4..794a42c1c46755b03a7e4acca867d0ad2a153935 100644 --- a/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java +++ b/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java @@ -43,7 +43,7 @@ public class Basic { static void checkAttributesOfDirectory(Path dir) throws IOException { - BasicFileAttributes attrs = Attributes.readBasicFileAttributes(dir); + BasicFileAttributes attrs = Files.readAttributes(dir, BasicFileAttributes.class); check(attrs.isDirectory(), "is a directory"); check(!attrs.isRegularFile(), "is not a regular file"); check(!attrs.isSymbolicLink(), "is not a link"); @@ -58,7 +58,7 @@ public class Basic { static void checkAttributesOfFile(Path dir, Path file) throws IOException { - BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file); + BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class); check(attrs.isRegularFile(), "is a regular file"); check(!attrs.isDirectory(), "is not a directory"); check(!attrs.isSymbolicLink(), "is not a link"); @@ -73,8 +73,8 @@ public class Basic { // copy last-modified time and file create time from directory to file, // re-read attribtues, and check they match BasicFileAttributeView view = - file.getFileAttributeView(BasicFileAttributeView.class); - BasicFileAttributes dirAttrs = Attributes.readBasicFileAttributes(dir); + Files.getFileAttributeView(file, BasicFileAttributeView.class); + BasicFileAttributes dirAttrs = Files.readAttributes(dir, BasicFileAttributes.class); view.setTimes(dirAttrs.lastModifiedTime(), null, null); if (dirAttrs.creationTime() != null) { view.setTimes(null, null, dirAttrs.creationTime()); @@ -95,8 +95,8 @@ public class Basic { static void checkAttributesOfLink(Path link) throws IOException { - BasicFileAttributes attrs = Attributes - .readBasicFileAttributes(link, LinkOption.NOFOLLOW_LINKS); + BasicFileAttributes attrs = + Files.readAttributes(link, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS); check(attrs.isSymbolicLink(), "is a link"); check(!attrs.isDirectory(), "is a directory"); check(!attrs.isRegularFile(), "is not a regular file"); @@ -108,11 +108,8 @@ public class Basic { { // create file Path file = dir.resolve("foo"); - OutputStream out = file.newOutputStream(); - try { + try (OutputStream out = Files.newOutputStream(file)) { out.write("this is not an empty file".getBytes("UTF-8")); - } finally { - out.close(); } // check attributes of directory and file @@ -122,7 +119,7 @@ public class Basic { // symbolic links may be supported Path link = dir.resolve("link"); try { - link.createSymbolicLink( file ); + Files.createSymbolicLink(link, file); } catch (UnsupportedOperationException x) { return; } catch (IOException x) { diff --git a/test/java/nio/file/attribute/DosFileAttributeView/Basic.java b/test/java/nio/file/attribute/DosFileAttributeView/Basic.java index bac02d22dfccaafd78f755946da13ce5c660273f..702c95050cce8c915aab5c94ab2ec549060528a2 100644 --- a/test/java/nio/file/attribute/DosFileAttributeView/Basic.java +++ b/test/java/nio/file/attribute/DosFileAttributeView/Basic.java @@ -74,27 +74,25 @@ public class Basic { static void readWriteTests(Path dir) throws IOException { // create "foo" and test that we can read/write each FAT attribute - Path file = dir.resolve("foo"); - file.createFile(); + Path file = Files.createFile(dir.resolve("foo")); try { - testAttributes(file - .getFileAttributeView(DosFileAttributeView.class)); + testAttributes(Files.getFileAttributeView(file, DosFileAttributeView.class)); // Following tests use a symbolic link so skip if not supported if (!TestUtil.supportsLinks(dir)) return; - Path link = dir.resolve("link").createSymbolicLink(file); + Path link = dir.resolve("link"); + Files.createSymbolicLink(link, file); // test following links - testAttributes(link - .getFileAttributeView(DosFileAttributeView.class)); + testAttributes(Files.getFileAttributeView(link, DosFileAttributeView.class)); // test not following links try { try { - testAttributes(link - .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS)); + testAttributes(Files + .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS)); } catch (IOException x) { // access to link attributes not supported return; @@ -103,32 +101,32 @@ public class Basic { // set all attributes on link // run test on target of link (which leaves them all un-set) // check that attributes of link remain all set - setAll(link - .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS), true); - testAttributes(link - .getFileAttributeView(DosFileAttributeView.class)); - DosFileAttributes attrs = Attributes.readDosFileAttributes(link, NOFOLLOW_LINKS); + setAll(Files + .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS), true); + testAttributes(Files + .getFileAttributeView(link, DosFileAttributeView.class)); + DosFileAttributes attrs = + Files.getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS) + .readAttributes(); check(attrs.isReadOnly()); check(attrs.isHidden()); check(attrs.isArchive()); check(attrs.isSystem()); - setAll(link - .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS), false); + setAll(Files + .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS), false); // set all attributes on target // run test on link (which leaves them all un-set) // check that attributes of target remain all set - setAll(link - .getFileAttributeView(DosFileAttributeView.class), true); - testAttributes(link - .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS)); - attrs = Attributes.readDosFileAttributes(link); + setAll(Files.getFileAttributeView(link, DosFileAttributeView.class), true); + testAttributes(Files + .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS)); + attrs = Files.getFileAttributeView(link, DosFileAttributeView.class).readAttributes(); check(attrs.isReadOnly()); check(attrs.isHidden()); check(attrs.isArchive()); check(attrs.isSystem()); - setAll(link - .getFileAttributeView(DosFileAttributeView.class), false); + setAll(Files.getFileAttributeView(link, DosFileAttributeView.class), false); } finally { TestUtil.deleteUnchecked(link); } @@ -143,7 +141,7 @@ public class Basic { try { // skip test if DOS file attributes not supported - if (!dir.getFileStore().supportsFileAttributeView("dos")) { + if (!Files.getFileStore(dir).supportsFileAttributeView("dos")) { System.out.println("DOS file attribute not supported."); return; } diff --git a/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java b/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java deleted file mode 100644 index 8307bac54bbed36cea69538ee9e330ef1490c0e4..0000000000000000000000000000000000000000 --- a/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 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 4313887 6838333 - * @summary Unit test for java.nio.file.attribute.FileStoreAttributeView - * @library ../.. - */ - -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * Simple unit test for FileStoreAttributeView that checks that the disk space - * attribtues are "close" to the equivalent values reported by java.io.File. - */ - -public class Basic { - - static final long K = 1024L; - static final long G = 1024L * 1024L * 1024L; - - /** - * Print out the disk space information for the given file system - */ - static void printFileStore(FileStore fs) throws IOException { - FileStoreSpaceAttributeView view = - fs.getFileStoreAttributeView(FileStoreSpaceAttributeView.class); - FileStoreSpaceAttributes attrs = view.readAttributes(); - - long total = attrs.totalSpace() / K; - long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / K; - long avail = attrs.usableSpace() / K; - - String s = fs.toString(); - if (s.length() > 20) { - System.out.println(s); - s = ""; - } - System.out.format("%-20s %12d %12d %12d\n", s, total, used, avail); - } - - /** - * Check that two values are within 1GB of each other - */ - static void checkWithin1GB(long value1, long value2) { - long diff = Math.abs(value1 - value2); - if (diff > G) - throw new RuntimeException("values differ by more than 1GB"); - } - - /** - * Check disk space on the file system of the given file - */ - static void checkSpace(Path file) throws IOException { - System.out.println(" -- check space -- "); - System.out.println(file); - - FileStore fs = file.getFileStore(); - System.out.format("Filesystem: %s\n", fs); - - // get values reported by java.io.File - File f = new File(file.toString()); - long total = f.getTotalSpace(); - long free = f.getFreeSpace(); - long usable = f.getUsableSpace(); - System.out.println("java.io.File"); - System.out.format(" Total: %d\n", total); - System.out.format(" Free: %d\n", free); - System.out.format(" Usable: %d\n", usable); - - // get values reported by the FileStoreSpaceAttributeView - FileStoreSpaceAttributes attrs = fs - .getFileStoreAttributeView(FileStoreSpaceAttributeView.class) - .readAttributes(); - System.out.println("java.nio.file.FileStoreSpaceAttributeView:"); - System.out.format(" Total: %d\n", attrs.totalSpace()); - System.out.format(" Free: %d\n", attrs.unallocatedSpace()); - System.out.format(" Usable: %d\n", attrs.usableSpace()); - - // check values are "close" - checkWithin1GB(total, attrs.totalSpace()); - checkWithin1GB(free, attrs.unallocatedSpace()); - checkWithin1GB(usable, attrs.usableSpace()); - - // get values by name - checkWithin1GB(total, (Long)fs.getAttribute("space:totalSpace")); - checkWithin1GB(free, (Long)fs.getAttribute("space:unallocatedSpace")); - checkWithin1GB(usable, (Long)fs.getAttribute("space:usableSpace")); - } - - public static void main(String[] args) throws IOException { - // print out the disk space information for all file systems - FileSystem fs = FileSystems.getDefault(); - for (FileStore store: fs.getFileStores()) { - printFileStore(store); - } - - Path dir = TestUtil.createTemporaryDirectory(); - try { - // check space using directory - checkSpace(dir); - - // check space using file - Path file = dir.resolve("foo").createFile(); - checkSpace(file); - - } finally { - TestUtil.removeAll(dir); - } - } -} diff --git a/test/java/nio/file/attribute/FileTime/Basic.java b/test/java/nio/file/attribute/FileTime/Basic.java index 2a79a1a6d7e4cb11c182321100fbc61117f7b14d..f907c00f871ff65b33ab1af3f13fdc1699fd855c 100644 --- a/test/java/nio/file/attribute/FileTime/Basic.java +++ b/test/java/nio/file/attribute/FileTime/Basic.java @@ -29,13 +29,16 @@ import java.nio.file.attribute.FileTime; import java.util.concurrent.TimeUnit; import static java.util.concurrent.TimeUnit.*; -import java.io.IOException; +import java.util.Random; public class Basic { - public static void main(String[] args) throws IOException { + static final Random rand = new Random(); + + public static void main(String[] args) { long now = System.currentTimeMillis(); long tomorrowInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) + 1; + long yesterdayInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) - 1; // equals eq(now, MILLISECONDS, now, MILLISECONDS); @@ -50,6 +53,29 @@ public class Basic { cmp(now, MILLISECONDS, now+1234, MILLISECONDS, -1); cmp(tomorrowInDays, DAYS, now, MILLISECONDS, 1); cmp(now, MILLISECONDS, tomorrowInDays, DAYS, -1); + cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1); + cmp(now, MILLISECONDS, yesterdayInDays, DAYS, 1); + cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1); + cmp(Long.MAX_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, 1); + cmp(Long.MAX_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, 1); + cmp(Long.MIN_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, -1); + cmp(Long.MIN_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, -1); + + // to(TimeUnit) + to(MILLISECONDS.convert(1, DAYS) - 1, MILLISECONDS); + to(MILLISECONDS.convert(1, DAYS) + 0, MILLISECONDS); + to(MILLISECONDS.convert(1, DAYS) + 1, MILLISECONDS); + to(1, MILLISECONDS); + to(0, MILLISECONDS); + to(1, MILLISECONDS); + to(MILLISECONDS.convert(-1, DAYS) - 1, MILLISECONDS); + to(MILLISECONDS.convert(-1, DAYS) + 0, MILLISECONDS); + to(MILLISECONDS.convert(-1, DAYS) + 1, MILLISECONDS); + for (TimeUnit unit: TimeUnit.values()) { + for (int i=0; i<100; i++) { to(rand.nextLong(), unit); } + to(Long.MIN_VALUE, unit); + to(Long.MAX_VALUE, unit); + } // toString ts(1L, DAYS, "1970-01-02T00:00:00Z"); @@ -59,6 +85,8 @@ public class Basic { ts(1L, MILLISECONDS, "1970-01-01T00:00:00.001Z"); ts(1L, MICROSECONDS, "1970-01-01T00:00:00.000001Z"); ts(1L, NANOSECONDS, "1970-01-01T00:00:00.000000001Z"); + ts(999999999L, NANOSECONDS, "1970-01-01T00:00:00.999999999Z"); + ts(9999999999L, NANOSECONDS, "1970-01-01T00:00:09.999999999Z"); ts(-1L, DAYS, "1969-12-31T00:00:00Z"); ts(-1L, HOURS, "1969-12-31T23:00:00Z"); @@ -67,6 +95,8 @@ public class Basic { ts(-1L, MILLISECONDS, "1969-12-31T23:59:59.999Z"); ts(-1L, MICROSECONDS, "1969-12-31T23:59:59.999999Z"); ts(-1L, NANOSECONDS, "1969-12-31T23:59:59.999999999Z"); + ts(-999999999L, NANOSECONDS, "1969-12-31T23:59:59.000000001Z"); + ts(-9999999999L, NANOSECONDS, "1969-12-31T23:59:50.000000001Z"); ts(-62135596799999L, MILLISECONDS, "0001-01-01T00:00:00.001Z"); ts(-62135596800000L, MILLISECONDS, "0001-01-01T00:00:00Z"); @@ -114,9 +144,24 @@ public class Basic { throw new RuntimeException("should not be equal"); } - static void ts(long v, TimeUnit y, String expected) { - String s = FileTime.from(v, y).toString(); - if (!s.equals(expected)) - throw new RuntimeException("unexpected format"); + static void to(long v, TimeUnit unit) { + FileTime t = FileTime.from(v, unit); + for (TimeUnit u: TimeUnit.values()) { + long result = t.to(u); + long expected = u.convert(v, unit); + if (result != expected) { + throw new RuntimeException("unexpected result"); + } + } + } + + static void ts(long v, TimeUnit unit, String expected) { + String result = FileTime.from(v, unit).toString(); + if (!result.equals(expected)) { + System.err.format("FileTime.from(%d, %s).toString() failed\n", v, unit); + System.err.format("Expected: %s\n", expected); + System.err.format(" Got: %s\n", result); + throw new RuntimeException(); + } } } diff --git a/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java b/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java index f3ff3584964871533ed222a94cfa552677d69413..7d948b9bd3e1001de97cbd56aac930960b9b8204 100644 --- a/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java +++ b/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java @@ -49,9 +49,8 @@ public class Basic { Set perms = PosixFilePermissions.fromString(mode); // change permissions and re-read them. - Attributes.setPosixFilePermissions(file, perms); - Set current = Attributes - .readPosixFileAttributes(file).permissions(); + Files.setPosixFilePermissions(file, perms); + Set current = Files.getPosixFilePermissions(file); if (!current.equals(perms)) { throw new RuntimeException("Actual permissions: " + PosixFilePermissions.toString(current) + ", expected: " + @@ -59,8 +58,8 @@ public class Basic { } // repeat test using setAttribute/getAttribute - file.setAttribute("posix:permissions", perms); - current = (Set)file.getAttribute("posix:permissions"); + Files.setAttribute(file, "posix:permissions", perms); + current = (Set)Files.getAttribute(file, "posix:permissions"); if (!current.equals(perms)) { throw new RuntimeException("Actual permissions: " + PosixFilePermissions.toString(current) + ", expected: " + @@ -97,25 +96,25 @@ public class Basic { FileAttribute> attr = PosixFilePermissions.asFileAttribute(requested); System.out.format("create file with mode: %s\n", mode); - file.createFile(attr); + Files.createFile(file, attr); try { - checkSecure(requested, file - .getFileAttributeView(PosixFileAttributeView.class) - .readAttributes() - .permissions()); + checkSecure(requested, + Files.getFileAttributeView(file, PosixFileAttributeView.class) + .readAttributes() + .permissions()); } finally { - file.delete(); + Files.delete(file); } System.out.format("create directory with mode: %s\n", mode); - file.createDirectory(attr); + Files.createDirectory(file, attr); try { - checkSecure(requested, file - .getFileAttributeView(PosixFileAttributeView.class) - .readAttributes() - .permissions()); + checkSecure(requested, + Files.getFileAttributeView(file, PosixFileAttributeView.class) + .readAttributes() + .permissions()); } finally { - file.delete(); + Files.delete(file); } } @@ -130,11 +129,11 @@ public class Basic { // create file and test updating and reading its permissions Path file = dir.resolve("foo"); System.out.format("create %s\n", file); - file.createFile(); + Files.createFile(file); try { // get initial permissions so that we can restore them later - PosixFileAttributeView view = file - .getFileAttributeView(PosixFileAttributeView.class); + PosixFileAttributeView view = + Files.getFileAttributeView(file, PosixFileAttributeView.class); Set save = view.readAttributes() .permissions(); @@ -165,7 +164,7 @@ public class Basic { view.setPermissions(save); } } finally { - file.delete(); + Files.delete(file); } // create link (to file that doesn't exist) and test reading of @@ -173,15 +172,18 @@ public class Basic { if (TestUtil.supportsLinks(dir)) { Path link = dir.resolve("link"); System.out.format("create link %s\n", link); - link.createSymbolicLink(file); + Files.createSymbolicLink(link, file); try { - PosixFileAttributes attrs = Attributes - .readPosixFileAttributes(link, NOFOLLOW_LINKS); + PosixFileAttributes attrs = + Files.getFileAttributeView(link, + PosixFileAttributeView.class, + NOFOLLOW_LINKS) + .readAttributes(); if (!attrs.isSymbolicLink()) { throw new RuntimeException("not a link"); } } finally { - link.delete(); + Files.delete(link); } } @@ -235,12 +237,12 @@ public class Basic { Path file = dir.resolve("gus"); System.out.format("create %s\n", file); - file.createFile(); + Files.createFile(file); try { // read attributes of directory to get owner/group - PosixFileAttributeView view = file - .getFileAttributeView(PosixFileAttributeView.class); + PosixFileAttributeView view = + Files.getFileAttributeView(file, PosixFileAttributeView.class); PosixFileAttributes attrs = view.readAttributes(); // set to existing owner/group @@ -248,13 +250,13 @@ public class Basic { view.setGroup(attrs.group()); // repeat test using set/getAttribute - UserPrincipal owner = (UserPrincipal)file.getAttribute("posix:owner"); - file.setAttribute("posix:owner", owner); - UserPrincipal group = (UserPrincipal)file.getAttribute("posix:group"); - file.setAttribute("posix:group", group); + UserPrincipal owner = (UserPrincipal)Files.getAttribute(file, "posix:owner"); + Files.setAttribute(file, "posix:owner", owner); + UserPrincipal group = (UserPrincipal)Files.getAttribute(file, "posix:group"); + Files.setAttribute(file, "posix:group", group); } finally { - file.delete(); + Files.delete(file); } System.out.println("OKAY"); @@ -272,7 +274,7 @@ public class Basic { .getUserPrincipalLookupService(); // read attributes of directory to get owner/group - PosixFileAttributes attrs = Attributes.readPosixFileAttributes(dir); + PosixFileAttributes attrs = Files.readAttributes(dir, PosixFileAttributes.class); // lookup owner and check it matches file's owner System.out.format("lookup: %s\n", attrs.owner().getName()); @@ -322,8 +324,8 @@ public class Basic { { System.out.println("-- Exceptions --"); - PosixFileAttributeView view = dir - .getFileAttributeView(PosixFileAttributeView.class); + PosixFileAttributeView view = + Files.getFileAttributeView(dir,PosixFileAttributeView.class); // NullPointerException try { @@ -355,7 +357,7 @@ public class Basic { } catch (NullPointerException x) { } try { - Set perms = new HashSet(); + Set perms = new HashSet<>(); perms.add(null); view.setPermissions(perms); throw new RuntimeException("NullPointerException not thrown"); @@ -377,7 +379,7 @@ public class Basic { public static void main(String[] args) throws IOException { Path dir = TestUtil.createTemporaryDirectory(); try { - if (!dir.getFileStore().supportsFileAttributeView("posix")) { + if (!Files.getFileStore(dir).supportsFileAttributeView("posix")) { System.out.println("PosixFileAttributeView not supported"); return; } diff --git a/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java b/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java index c6a807a45eccc68f3cfd52c0a859d3cce972ddce..a6af419223496809e1fd6aa24725779367232203 100644 --- a/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java +++ b/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java @@ -79,8 +79,8 @@ public class Basic { } static void test(Path file, LinkOption... options) throws IOException { - final UserDefinedFileAttributeView view = file - .getFileAttributeView(UserDefinedFileAttributeView.class, options); + final UserDefinedFileAttributeView view = + Files.getFileAttributeView(file, UserDefinedFileAttributeView.class, options); ByteBuffer buf = rand.nextBoolean() ? ByteBuffer.allocate(100) : ByteBuffer.allocateDirect(100); @@ -131,24 +131,24 @@ public class Basic { // Test: dynamic access String name = "user:" + ATTR_NAME; byte[] valueAsBytes = ATTR_VALUE.getBytes(); - file.setAttribute(name, valueAsBytes); - byte[] actualAsBytes = (byte[])file.getAttribute(name); + Files.setAttribute(file, name, valueAsBytes); + byte[] actualAsBytes = (byte[])Files.getAttribute(file, name); if (!Arrays.equals(valueAsBytes, actualAsBytes)) throw new RuntimeException("Unexpected attribute value"); - Map map = file.readAttributes(name); + Map map = Files.readAttributes(file, name); if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME))) throw new RuntimeException("Unexpected attribute value"); - map = file.readAttributes("user:*"); + map = Files.readAttributes(file, "user:*"); if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME))) throw new RuntimeException("Unexpected attribute value"); - map = file.readAttributes("user:DoesNotExist"); + map = Files.readAttributes(file, "user:DoesNotExist"); if (!map.isEmpty()) throw new RuntimeException("Map expected to be empty"); } static void miscTests(final Path file) throws IOException { - final UserDefinedFileAttributeView view = file - .getFileAttributeView(UserDefinedFileAttributeView.class); + final UserDefinedFileAttributeView view = + Files.getFileAttributeView(file, UserDefinedFileAttributeView.class); view.write(ATTR_NAME, ByteBuffer.wrap(ATTR_VALUE.getBytes())); // NullPointerException @@ -180,31 +180,31 @@ public class Basic { }}); expectNullPointerException(new Task() { public void run() throws IOException { - file.getAttribute(null); + Files.getAttribute(file, null); }}); expectNullPointerException(new Task() { public void run() throws IOException { - file.getAttribute("user:" + ATTR_NAME, (LinkOption[])null); + Files.getAttribute(file, "user:" + ATTR_NAME, (LinkOption[])null); }}); expectNullPointerException(new Task() { public void run() throws IOException { - file.setAttribute("user:" + ATTR_NAME, null); + Files.setAttribute(file, "user:" + ATTR_NAME, null); }}); expectNullPointerException(new Task() { public void run() throws IOException { - file.setAttribute(null, new byte[0]); + Files.setAttribute(file, null, new byte[0]); }}); expectNullPointerException(new Task() { public void run() throws IOException { - file.setAttribute("user: " + ATTR_NAME, new byte[0], (LinkOption[])null); + Files.setAttribute(file, "user: " + ATTR_NAME, new byte[0], (LinkOption[])null); }}); expectNullPointerException(new Task() { public void run() throws IOException { - file.readAttributes((String)null); + Files.readAttributes(file, (String)null); }}); expectNullPointerException(new Task() { public void run() throws IOException { - file.readAttributes("*", (LinkOption[])null); + Files.readAttributes(file, "*", (LinkOption[])null); }}); // Read-only buffer @@ -229,46 +229,50 @@ public class Basic { // create temporary directory to run tests Path dir = TestUtil.createTemporaryDirectory(); try { - if (!dir.getFileStore().supportsFileAttributeView("user")) { + if (!Files.getFileStore(dir).supportsFileAttributeView("user")) { System.out.println("UserDefinedFileAttributeView not supported - skip test"); return; } // test access to user defined attributes of regular file - Path file = dir.resolve("foo.html").createFile(); + Path file = dir.resolve("foo.html"); + Files.createFile(file); try { test(file); } finally { - file.delete(); + Files.delete(file); } - // test access to user define attributes of directory - file = dir.resolve("foo").createDirectory(); + // test access to user defined attributes of directory + Path subdir = dir.resolve("foo"); + Files.createDirectory(subdir); try { - test(file); + test(subdir); } finally { - file.delete(); + Files.delete(subdir); } // test access to user defined attributes of sym link if (TestUtil.supportsLinks(dir)) { Path target = dir.resolve("doesnotexist"); - Path link = dir.resolve("link").createSymbolicLink(target); + Path link = dir.resolve("link"); + Files.createSymbolicLink(link, target); try { test(link, NOFOLLOW_LINKS); } catch (IOException x) { // access to attributes of sym link may not be supported } finally { - link.delete(); + Files.delete(link); } } // misc. tests try { - file = dir.resolve("foo.txt").createFile(); + file = dir.resolve("foo.txt"); + Files.createFile(file); miscTests(dir); } finally { - file.delete(); + Files.delete(file); } } finally { diff --git a/test/java/nio/file/spi/SetDefaultProvider.java b/test/java/nio/file/spi/SetDefaultProvider.java index 7852edb717dcb733da054623b14816bf9cc6d9bb..e21be72985ab9d7c9e772f03c782fea565c84800 100644 --- a/test/java/nio/file/spi/SetDefaultProvider.java +++ b/test/java/nio/file/spi/SetDefaultProvider.java @@ -22,14 +22,13 @@ */ /* @test - * @bug 4313887 + * @bug 4313887 7006126 * @summary Unit test for java.nio.file.spi.FileSystemProvider * @build TestProvider SetDefaultProvider * @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider SetDefaultProvider */ import java.nio.file.*; -import java.nio.file.spi.*; public class SetDefaultProvider { public static void main(String[] args) throws Exception { diff --git a/test/java/nio/file/spi/TestProvider.java b/test/java/nio/file/spi/TestProvider.java index 248b568858fce0b152aa15c3a09c23bf8b123741..a604b6dfe7e4a132565aefd0a5950cd2deb4802f 100644 --- a/test/java/nio/file/spi/TestProvider.java +++ b/test/java/nio/file/spi/TestProvider.java @@ -24,6 +24,7 @@ import java.nio.file.spi.FileSystemProvider; import java.nio.file.*; import java.nio.file.attribute.*; +import java.nio.channels.SeekableByteChannel; import java.net.URI; import java.util.*; import java.io.IOException; @@ -34,7 +35,6 @@ public class TestProvider extends FileSystemProvider { public TestProvider(FileSystemProvider defaultProvider) { theFileSystem = new TestFileSystem(this); - } @Override @@ -57,6 +57,124 @@ public class TestProvider extends FileSystemProvider { throw new RuntimeException("not implemented"); } + @Override + public void setAttribute(Path file, String attribute, Object value, + LinkOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public Map readAttributes(Path file, String attributes, + LinkOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public A readAttributes(Path file, + Class type, + LinkOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public V getFileAttributeView(Path file, + Class type, + LinkOption... options) + { + throw new RuntimeException("not implemented"); + } + + + @Override + public void delete(Path file) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public void createSymbolicLink(Path link, Path target, FileAttribute... attrs) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public void createLink(Path link, Path existing) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public Path readSymbolicLink(Path link) throws IOException { + throw new RuntimeException("not implemented"); + } + + + @Override + public void copy(Path source, Path target, CopyOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public void move(Path source, Path target, CopyOption... options) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public DirectoryStream newDirectoryStream(Path dir, + DirectoryStream.Filter filter) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public void createDirectory(Path dir, FileAttribute... attrs) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + @Override + public SeekableByteChannel newByteChannel(Path file, + Set options, + FileAttribute... attrs) + throws IOException + { + throw new RuntimeException("not implemented"); + } + + + @Override + public boolean isHidden(Path file) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public FileStore getFileStore(Path file) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public boolean isSameFile(Path file, Path other) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public void checkAccess(Path file, AccessMode... modes) + throws IOException + { + throw new RuntimeException("not implemented"); + } + static class TestFileSystem extends FileSystem { private final TestProvider provider; @@ -105,7 +223,7 @@ public class TestProvider extends FileSystemProvider { } @Override - public Path getPath(String path) { + public Path getPath(String first, String... more) { throw new RuntimeException("not implemented"); } @@ -124,5 +242,4 @@ public class TestProvider extends FileSystemProvider { throw new RuntimeException("not implemented"); } } - }